Sending email with multiple attachments (Swift) - ios

I am wanting to send an email with multiple excel attachments.
The below code has func to create each file and save in a created user directory.
The files are saved fine.
The email is generated and sends fine.
My one issue that I cannot solve is: It is attaching TWO copies of each file, causing the email to have two sets of attached data.
The issue seems to be in the func configuredMailComposeViewController.
Can someone please help me fix the code so it will only send a single set of files?
class ExportToExcel: UIViewController, MFMailComposeViewControllerDelegate, UINavigationControllerDelegate {
var taskArr = [Export]()
var task: Export!
var noteID:Int = -1
var contactID:Int = -1
var companyID:Int = -1
let mailComposer = MFMailComposeViewController()
var fileNameNote = String()
var fileNameCompany = String()
var fileNameWC = String()
var fileNameBldg = String()
var fileNameCurrent = String()
var fileNameLoss = String()
fileprivate var contactDetails: ContactModel = ContactModel()
fileprivate var companyDetails: ContactModel = ContactModel()
fileprivate var quickNoteDetails: QuickNoteModel = QuickNoteModel()
fileprivate var bizDetails: BizDetailsModel = BizDetailsModel()
fileprivate var imageNames: Array<PhotoModel> = [PhotoModel]()
override func viewDidLoad() {
super.viewDidLoad()
// creating the "MeetingNotes" directory
self.createNewDir()
mailComposer.mailComposeDelegate = self
mailComposer.delegate = self
self.sendEmailButton()
}
func setFileLocation(_ fileName: String) -> URL {
let filemgr = FileManager.default
let dirPaths = filemgr.urls(for: .documentDirectory, in: .userDomainMask)
let docsURL = dirPaths[0].appendingPathComponent("MeetingNotes")
let path = docsURL.appendingPathComponent(fileName)
return path
}
func createNewDir() {
let filemgr = FileManager.default
let dirPaths = filemgr.urls(for: .documentDirectory, in: .userDomainMask)
let docsURL = dirPaths[0]
let newDir = docsURL.appendingPathComponent("MeetingNotes").path
do {
try filemgr.createDirectory(atPath: newDir,
withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
}
}
func createNoteCSV() -> Void {
fileNameNote = ("\(task.Company_Name)-\(task.Note_Date)-Note.xls").removeSpaces
let path = setFileLocation(fileNameNote)
var csvText = "Note Date,Note Details,Company Name,Company Phone,Contact Name,Contact Office,Contact Mobile,Contact Email,Coverages,BOP SIC,NAICS\n"
let newLine = "\(task.Note_Date),\(task.Notes.removeCommas),\(task.Company_Name),\(task.Company_Phone),\(task.Contact_Name),\(task.Contact_Office),\(task.Contact_Mobile),\(task.Contact_Email),\(task.Coverages),\(task.BOP_SIC),\(task.NAICS)"
csvText.append(newLine)
do {
try csvText.write(to: path, atomically: true, encoding: String.Encoding.utf8)
let url = path
let activityViewController = UIActivityViewController(activityItems: [url as Any] , applicationActivities: nil)
DispatchQueue.main.async {
self.present(activityViewController, animated: true, completion: nil)
}
} catch {
print("Failed to create file ")
print("\(error)")
}
}
func createBldgCSV() -> Void {
if !BuildingsArrayExport.array.isEmpty {
fileNameBldg = ("\(task.Company_Name)-\(task.Note_Date)-Bldg.xls").removeSpaces
let path = setFileLocation(fileNameBldg)
var csvText = "Note Date,Company Name,Bldg Nickname,Bldg Address, Bldg City, Bldg State, Bldg Zipcode,Deductible,Bldg Year,Office SqFt,Bldg SqFt,Floors,Roof Type,Construction Type,Bldg Type,Bldg Value,Yr Heat Replaced,Yr Wire Replaced,Yr Roof Replaced,Yr Plumbing Replaced,Pct Bldg Occupied,Pct Tenant Occupied,Pct Sprinkler,Responible for Parking lot,Alarm Type\n"
let items = BuildingsArrayExport.array
for item in items {
let address = "\(item.address1) \(item.address2)"
let newLine = "\(task.Note_Date),\(task.Company_Name),\(item.nickName),\(address.removeCommas),\(item.city.removeCommas),\(item.state),\(item.zipCode),\(item.deductible.removeCommas),\(item.buildingYr),\(item.officeSqFt),\(item.buildingSqFt),\(item.buildingStories),\(item.roofType.removeCommas),\(item.constructionType.removeCommas),\(item.buildingType.removeCommas),\(item.buildingValue.removeCommas),\(item.heatingReplaced),\(item.wiringReplaced),\(item.roofReplaced),\(item.plumbingReplaced),\(item.percentUnoccupied),\(item.percentOthersOccupied),\(item.sprinklerSystem),\(item.responsibleForParkingLot),\(item.alarmType)\n"
csvText.append(newLine)
}
do {
try csvText.write(to: path, atomically: true, encoding: String.Encoding.utf8)
let url = path
let activityViewController = UIActivityViewController(activityItems: [url as Any] , applicationActivities: nil)
DispatchQueue.main.async {
self.present(activityViewController, animated: true, completion: nil)
}
} catch {
print("Failed to create file ")
print("\(error)")
}
} else {
return
}
}
// more of the same func types, but deleted to reduce post size
func sendEmailButton() {
guard appOwnerEmail != nil else {
return
}
self.createNoteCSV()
self.createCompanyCSV()
self.createBldgCSV()
self.createWcCSV()
self.createLossCSV()
self.createCurrentCSV()
let mailComposeViewController = configuredMailComposeViewController(appOwnerEmail)
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
// During this function, it will post all data twice. This includes
// 2 x each xls and 2 x each image.
// The "do" portion of this func gets executed twice.
// That is the issue
func configuredMailComposeViewController(_ email: String) -> MFMailComposeViewController {
mailComposer.setSubject("\(task.Company_Name) meeting note")
mailComposer.setMessageBody("Meetings note details)", isHTML: true)
mailComposer.setToRecipients([appOwnerEmail])
mailComposer.setCcRecipients([""])
mailComposer.setBccRecipients([""])
let filemgr = FileManager.default
let dirPaths = filemgr.urls(for: .documentDirectory,
in: .userDomainMask)
do {
let fileNoteURL = setFileLocation(fileNameNote)
let attachmentNoteData = try Data(contentsOf: fileNoteURL)
mailComposer.addAttachmentData(attachmentNoteData, mimeType: "application/xls", fileName: fileNameNote)
let fileCompanyURL = setFileLocation(fileNameCompany)
let attachmentCompanyData = try Data(contentsOf: fileCompanyURL)
mailComposer.addAttachmentData(attachmentCompanyData, mimeType: "application/xls", fileName: fileNameCompany)
if !BuildingsArrayExport.array.isEmpty {
let fileBldgURL = setFileLocation(fileNameBldg)
let attachmentBldgData = try Data(contentsOf: fileBldgURL)
mailComposer.addAttachmentData(attachmentBldgData, mimeType: "application/xls", fileName: fileNameBldg)
}
if !WorkersCompArrayExport.array.isEmpty {
let fileWCURL = setFileLocation(fileNameWC)
let attachmentWCData = try Data(contentsOf: fileWCURL)
mailComposer.addAttachmentData(attachmentWCData, mimeType: "application/xls", fileName: fileNameWC)
}
if !CurrentPolicyArrayExport.array.isEmpty {
let fileCPURL = setFileLocation(fileNameCurrent)
let attachmentCPData = try Data(contentsOf: fileCPURL)
mailComposer.addAttachmentData(attachmentCPData, mimeType: "application/xls", fileName: fileNameCurrent)
}
if !LossItemsArrayExport.array.isEmpty {
let fileLossURL = setFileLocation(fileNameLoss)
let attachmentLossData = try Data(contentsOf: fileLossURL)
mailComposer.addAttachmentData(attachmentLossData, mimeType: "application/xls", fileName: fileNameLoss)
}
imageNames = AppDelegate.getUserDatabase().getPhotoList(noteID)
for imageName in imageNames {
let name = imageName.name
let imageURL = dirPaths[0].appendingPathComponent(name)
let attachmentImages = try Data(contentsOf: imageURL)
mailComposer.addAttachmentData(attachmentImages, mimeType: "application/jpg", fileName: name)
mailComposer.mailComposeDelegate = self
self.present(mailComposer, animated: true
, completion: nil)
}
if MFMailComposeViewController.canSendMail() {
self.present(mailComposer, animated: true
, completion: nil)
} else {
print("Emails not configured")
}
} catch let error {
print("We csv encountered error \(error.localizedDescription)")
}
return mailComposer
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertController(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", preferredStyle: .alert)
sendMailErrorAlert.addAction(UIAlertAction(title: "OK", style: .default) { _ in })
self.present(sendMailErrorAlert, animated: true){}
self.dismiss(animated: false, completion: nil)
}
public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
switch result {
case .cancelled:
print("Mail cancelled")
case .saved:
AppDelegate.getUserDatabase().recordEmailSent(noteID)
print("Mail saved")
case .sent:
AppDelegate.getUserDatabase().recordEmailSent(noteID)
print("Mail sent")
case .failed:
break
#unknown default:
fatalError()
}
controller.dismiss(animated: true) {
self.dismiss(animated: true, completion: nil)
}
}
}

I found the error and it was being caused by a different viewController.
I am leaving the code up and lengthy to support someone else who may need help exporting multiple file via email.

Related

While sharing a vcf file in iOS , the file is not getting attached in mail using swift

I'm trying to share a vcf file using UIActivityViewController. It shares the file with all other options except mail. It just opens the mail composer without any attachment. Here's my code:
guard let directoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
return
}
var filename = NSUUID().uuidString
if let fullname = CNContactFormatter().string(from: contact) {
filename = fullname.components(separatedBy: " ").joined(separator: " ")
}
let fileURL = directoryURL
.appendingPathComponent(filename)
.appendingPathExtension("vcf")
do{
let data = try CNContactVCardSerialization.data(with: [contact])
print("filename: \(filename)")
print("contact: \(String(describing: String(data: data, encoding: String.Encoding.utf8)))")
try data.write(to: fileURL, options: [.atomicWrite])
}
catch{
print(error.localizedDescription)
}
let activityViewController = UIActivityViewController(
activityItems: [fileURL],
applicationActivities: nil
)
present(activityViewController, animated: true, completion: nil)
I want to attach this contact as a vcf file in mail app when user selects mail option for sharing.
Use mimeType #"text/x-vcard" for a vcf file in addAttachmentData:mimeType:fileName of MFMailComposeViewController
Here is draft code using your's i have tested.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let contactStore = CNContactStore()
var contacts = [CNContact]()
let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactVCardSerialization.descriptorForRequiredKeys()]
let request = CNContactFetchRequest(keysToFetch: keys)
do {
try contactStore.enumerateContacts(with: request) {
(contact, stop) in
// Array containing all unified contacts from everywhere
contacts.append(contact)
}
self.shareContact(contact: contacts.first!)
}
catch {
print("unable to fetch contacts")
}
}
func shareContact(contact:CNContact) {
guard let directoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
return
}
var filename = NSUUID().uuidString
if let fullname = CNContactFormatter().string(from: contact) {
filename = fullname.components(separatedBy: " ").joined(separator: " ")
}
let fileURL = directoryURL
.appendingPathComponent(filename)
.appendingPathExtension("vcf")
do{
let data = try CNContactVCardSerialization.data(with: [contact])
print("filename: \(filename)")
print("contact: \(String(describing: String(data: data, encoding: String.Encoding.utf8)))")
print(fileURL)
try data.write(to: fileURL, options: [.atomicWrite])
}
catch{
print(error.localizedDescription)
}
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { (t) in
self.showActivityController(fileURL: fileURL)
t.invalidate()
}
}
func showActivityController (fileURL:URL) {
let activityViewController = UIActivityViewController(
activityItems: [fileURL],
applicationActivities: nil
)
present(activityViewController, animated: true, completion: nil)
}
}

Uploading recording to Firebase with Swift

I've been trying to upload audio recording right after user stops recording to the Firebase. But it doesn't do anything apart from creating a new folder named "audio".
Code I'm using for starting and stopping recording
#IBAction func recordAudio(_ sender: AnyObject) {
recordingLabel.text = "Recording in progress"
stopRecordingButton.isEnabled = true
recordButton.isEnabled = false
let dirPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)[0] as String
let recordingName = "recordedVoice.wav"
let pathArray = [dirPath, recordingName]
let filePath = URL(string: pathArray.joined(separator: "/"))
let session = AVAudioSession.sharedInstance()
try! session.setCategory(AVAudioSessionCategoryPlayAndRecord, with:AVAudioSessionCategoryOptions.defaultToSpeaker)
try! audioRecorder = AVAudioRecorder(url: filePath!, settings: [:])
audioRecorder.delegate = self
audioRecorder.isMeteringEnabled = true
audioRecorder.prepareToRecord()
audioRecorder.record()
}
#IBAction func stopRecording(_ sender: AnyObject) {
print("Stop recording button was pressed")
recordButton.isEnabled = true
stopRecordingButton.isEnabled = false
recordingLabel.text = "Tap to Record"
audioRecorder.stop()
let audioSession = AVAudioSession.sharedInstance()
try! audioSession.setActive(false)
}
code I'm using for uploading to Firebase
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
print("finished recording")
let storageRef = Storage.storage().reference().child("audio/recordedVoice.wav")
if let uploadData = AVFileType(self.recordedVoice.wav!) {
storageRef.put(uploadData, metadata: nil) {(metadata, error) in
if error != nil {
print(error)
return
}
}
}
}
Please help me!
Try:
let audioName = NSUUID().uuidString //You'll get unique audioFile name
let storageRef = Storage.storage().reference().child("audio").child(audioName)
let metadata = StorageMetadata()
metadata.contentType = "audio/wav"
if let uploadData = AVFileType(self.recordedVoice.wav!) {
storageRef.putData(uploadData, metadata: metadata) { (metadata, err) in
if err != nil {
//print(err)
return
}
if let _ = metadata?.downloadURL()?.absoluteString {
print("uploading done!")
}
}
}
so I have been working on this for hours and here is my answer:
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func getFileURL() -> URL {
let path = getDocumentsDirectory()
let filePath = path.appendingPathComponent(K.fileName)
return filePath
}
let referance = storage.reference()
let mediaFolder = referance.child("media")
let id = UUID().uuidString // using uuid to give uniq names to audiofiles preventing overwrite
let mediaRef = mediaFolder.child(id + K.fileName) // creating file referance using uuid + filename
let path = getFileURL() // getting filepath
do {
let data = try Data(contentsOf: path) // getting data from filepath
mediaRef.putData(data) { metadata, error in
if error != nil {
self.showAlert(title: "Error", message: error?.localizedDescription, cancelButtonTitle: "cancel", handler: nil)
} else {
mediaRef.downloadURL { url, error in
let url = url?.absoluteString
print(url)
}
}
}
print("record has come")
} catch {
print("error cant get audio file")
}
I'm relatively new at coding and still learning. So that my answer may not be the best and shortest. But This worked for me.

CKAsset (NSData) to UIWebView to share with ActivityViewController

I have PDF Files as CKAssets, which are called and presented in a UIWebView without issue. I have managed to manipulate the code so as the CKAsset will present in a ActivityViewController, but this is within the func method and I wish to assign this part to an Action button. My question is how can I call a few lines within a function? or have sufficient references outside the func to make the action button work?
Here is the func code -
func queryRecord() {
let container = CKContainer.default()
let publicDatabase = container.publicCloudDatabase
let predicate = NSPredicate(format: "recordID = %#", CKRecordID(recordName : documentID))
let query = CKQuery(recordType: "Documents", predicate: predicate)
publicDatabase.perform(query, inZoneWith: nil, completionHandler: ({results, error in
if (error != nil) {
DispatchQueue.main.async() {
self.notifyUser("Cloud Access Error", message: error!.localizedDescription)
}
} else {
if results!.count > 0 {
let record = results![0]
print(record)
DispatchQueue.main.async() {
let docTitle = record.object(forKey: "documentName") as! String
self.title = "\(docTitle)"
let docType = record.object(forKey: "documentType") as! String
if docType == "PDF" || docType == "pdf" {
if let asset1 = record.object(forKey: "documentFile") as? CKAsset {
let doc1Data : NSData? = NSData(contentsOf:asset1.fileURL)
self.docWebView.load(doc1Data! as Data, mimeType: "application/pdf", textEncodingName: "UTF-8", baseURL: NSURL() as URL)
let filenameURL = [(asset1.fileURL)]
let activityController = UIActivityViewController(activityItems: filenameURL, applicationActivities: nil)
self.present(activityController, animated: true, completion: nil)
}
} else {
I have tried to reference filenameURL outside the code, but it does not recognise that filenameURL is no member of the class.
I figured it out (I think). Here goes -
I changed
let filenameURL = [(asset1.fileURL)]
to
self.filenameURL = [(asset1.fileURL)]
then added
var filenameURL : Any?
to the ViewController Class. Which allowed me to add the relevant code to the actionButton -
#IBAction func activityVCButton(_ sender: UIBarButtonItem) {
let activityController = UIActivityViewController(activityItems: (filenameURL as? [Any])!, applicationActivities: nil)
self.present(activityController, animated: true, completion: nil)
}
I think the key, which I seemed to be missing was the Any?, but I am happy to be corrected if there was something more fundamental I was missing.

How to Export Core Data to CSV in Swift 3?

I want to export all data of my entity "Log". I found this Code Example:
https://gist.github.com/kenechilearnscode/2d5d35f550f593332319
But this won't work for me. It donĀ“t add the Data of Core Data, the only output I get is: "This is what the app will export: date, label, typ"
My Core Data Entity is "Log" with the attributes: date(type:date), labe1(type:String) and typ(type:Double).
How can I export the Core Data to an CSV-File and send it via Mail?
Thanks for any help :)
var logs : [Log] = []
func createExportString() -> String {
var date: NSDate? = NSDate()
var labe1: String?
var typ: Double
var export: String = NSLocalizedString("date, label, typ, \n", comment: "")
for (index, log) in logs.enumerated() {
if index < logs.count - 1 {
date = Date() as? NSDate
label = log.value(forKey: "time") as? String
typ = (log.value(forKey: "type") as? Double)!
let dateString = "\(log.date!)"
let labelString = "\(log.labe1!)"
let typeString = "\(log.typ)"
export += dateString + "," + labelString + "," + typeString + "," + "\n"
}
}
print("This is what the app will export: \(export)")
return export
}
func exportDatabase() {
var exportString = createExportString()
saveAndExport(exportString: exportString)
}
func saveAndExport(exportString: String) {
let exportFilePath = NSTemporaryDirectory() + "export.csv"
let exportFileURL = NSURL(fileURLWithPath: exportFilePath)
FileManager.default.createFile(atPath: exportFilePath, contents: NSData() as Data, attributes: nil)
var fileHandleError: NSError? = nil
var fileHandle: FileHandle? = nil
do {
fileHandle = try FileHandle(forWritingTo: exportFileURL as URL)
} catch {
print("Error with fileHandle")
}
if fileHandle != nil {
fileHandle!.seekToEndOfFile()
let csvData = exportString.data(using: String.Encoding.utf8, allowLossyConversion: false)
fileHandle!.write(csvData!)
fileHandle!.closeFile()
let firstActivityItem = NSURL(fileURLWithPath: exportFilePath)
let activityViewController : UIActivityViewController = UIActivityViewController(
activityItems: [firstActivityItem], applicationActivities: nil)
activityViewController.excludedActivityTypes = [
UIActivityType.assignToContact,
UIActivityType.saveToCameraRoll,
UIActivityType.postToFlickr,
UIActivityType.postToVimeo,
UIActivityType.postToTencentWeibo
]
self.present(activityViewController, animated: true, completion: nil)
}
}
EDIT:
I try to add these:
let context = DatabaseController.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Log")
let result = try! NSManagedObjectContext.execute(fetchRequest)
logs = [result]
But I get the error: "Use of instance member 'execute' on type 'NSManagedObjectContext'; did you mean to use a value of type 'NSManagedObjectContext' instead?"
EDIT 2:
With these:
do {
let results = try context.execute(fetchRequest)
}
catch {
print(error)
}
I get the error on the line where "logs = [result]:
Use of unresolved identifier 'result'
This my solution that I use for Swift 4.2.
UPDATED to match code in repository.
import UIKit
import CoreData
class ViewController: UIViewController {
var itemid = 178
var nametext = "Jones3"
var amountDouble = 68
var inventoryDate: Date? = Date()
var stockStatus = true
var fetchedStatsArray: [NSManagedObject] = []
let context = CoreDataStack.context
override func viewDidLoad() {
super.viewDidLoad()
// This add a new record every time the app is run
storeTranscription()
// Loads the current data
getTranscriptions()
}
#IBAction func exportButton(_ sender: UIButton) {
exportDatabase()
}
func storeTranscription() {
//retrieve the entity that we just created
let entity = NSEntityDescription.entity(forEntityName: "ItemList", in: context)
let transc = NSManagedObject(entity: entity!, insertInto: context) as! ItemList
//set the entity values
transc.itemID = Double(itemid)
transc.productname = nametext
transc.amount = Double(amountDouble)
transc.stock = stockStatus
transc.inventoryDate = inventoryDate
//save the object
do {
try context.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
func getTranscriptions () {
//create a fetch request, telling it about the entity
let fetchRequest: NSFetchRequest<ItemList> = ItemList.fetchRequest()
do {
//go get the results
let searchResults = try context.fetch(fetchRequest)
fetchedStatsArray = searchResults as [NSManagedObject]
//I like to check the size of the returned results!
print ("num of results = \(searchResults.count)")
//You need to convert to NSManagedObject to use 'for' loops
for trans in searchResults as [NSManagedObject] {
//get the Key Value pairs (although there may be a better way to do that...
print("\(trans.value(forKey: "productname")!)")
let mdate = trans.value(forKey: "inventoryDate") as! Date
print(mdate)
}
} catch {
print("Error with request: \(error)")
}
}
func exportDatabase() {
let exportString = createExportString()
saveAndExport(exportString: exportString)
}
func saveAndExport(exportString: String) {
let exportFilePath = NSTemporaryDirectory() + "itemlist.csv"
let exportFileURL = NSURL(fileURLWithPath: exportFilePath)
FileManager.default.createFile(atPath: exportFilePath, contents: NSData() as Data, attributes: nil)
//var fileHandleError: NSError? = nil
var fileHandle: FileHandle? = nil
do {
fileHandle = try FileHandle(forWritingTo: exportFileURL as URL)
} catch {
print("Error with fileHandle")
}
if fileHandle != nil {
fileHandle!.seekToEndOfFile()
let csvData = exportString.data(using: String.Encoding.utf8, allowLossyConversion: false)
fileHandle!.write(csvData!)
fileHandle!.closeFile()
let firstActivityItem = NSURL(fileURLWithPath: exportFilePath)
let activityViewController : UIActivityViewController = UIActivityViewController(
activityItems: [firstActivityItem], applicationActivities: nil)
activityViewController.excludedActivityTypes = [
UIActivity.ActivityType.assignToContact,
UIActivity.ActivityType.saveToCameraRoll,
UIActivity.ActivityType.postToFlickr,
UIActivity.ActivityType.postToVimeo,
UIActivity.ActivityType.postToTencentWeibo
]
self.present(activityViewController, animated: true, completion: nil)
}
}
func createExportString() -> String {
var itemIDvar: NSNumber?
var productNamevar: String?
var amountvar: NSNumber?
var stockvar: Bool?
var export: String = NSLocalizedString("itemID, productName, Amount \n", comment: "")
for (index, itemList) in fetchedStatsArray.enumerated() {
if index <= fetchedStatsArray.count - 1 {
itemIDvar = itemList.value(forKey: "itemID") as! NSNumber?
productNamevar = itemList.value(forKey: "productname") as! String?
amountvar = itemList.value(forKey: "amount") as! NSNumber?
stockvar = itemList.value(forKey: "stock") as! Bool?
let inventoryDatevar = itemList.value(forKey: "inventoryDate") as! Date
let itemIDString = itemIDvar
let procductNameSting = productNamevar
let amountSting = amountvar
let stockSting = stockvar
let inventoryDateSting = "\(inventoryDatevar)"
export += "\(itemIDString!),\(procductNameSting!),\(stockSting!),\(amountSting!),\(inventoryDateSting) \n"
}
}
print("This is what the app will export: \(export)")
return export
}
}
Project Files

How to share image in instagram?Swift

Sorry for the question without a code.But i didn't find anywhere to look for.
I want to share image with title in instagram? How can i do that?
Any help would be great
if you don't want to use UIDocumentInteractionController
SWIFT 5 update
import Photos
...
func postImageToInstagram(image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
#objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if error != nil {
print(error)
}
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
if let lastAsset = fetchResult.firstObject as? PHAsset {
let url = URL(string: "instagram://library?LocalIdentifier=\(lastAsset.localIdentifier)")!
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
} else {
let alertController = UIAlertController(title: "Error", message: "Instagram is not installed", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
}
}
Swift 3.0 Version :
#IBAction func shareInstagram(_ sender: Any) {
DispatchQueue.main.async {
//Share To Instagram:
let instagramURL = URL(string: "instagram://app")
if UIApplication.shared.canOpenURL(instagramURL!) {
let imageData = UIImageJPEGRepresentation(image, 100)
let writePath = (NSTemporaryDirectory() as NSString).appendingPathComponent("instagram.igo")
do {
try imageData?.write(to: URL(fileURLWithPath: writePath), options: .atomic)
} catch {
print(error)
}
let fileURL = URL(fileURLWithPath: writePath)
self.documentController = UIDocumentInteractionController(url: fileURL)
self.documentController.delegate = self
self.documentController.uti = "com.instagram.exlusivegram"
if UIDevice.current.userInterfaceIdiom == .phone {
self.documentController.presentOpenInMenu(from: self.view.bounds, in: self.view, animated: true)
} else {
self.documentController.presentOpenInMenu(from: self.IGBarButton, animated: true)
}
} else {
print(" Instagram is not installed ")
}
}
}
class viewController: UIViewController, UIDocumentInteractionControllerDelegate {
var yourImage: UIImage?
var documentController: UIDocumentInteractionController!
func shareToInstagram() {
let instagramURL = NSURL(string: "instagram://app")
if (UIApplication.sharedApplication().canOpenURL(instagramURL!)) {
let imageData = UIImageJPEGRepresentation(yourImage!, 100)
let captionString = "caption"
let writePath = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("instagram.igo")
if imageData?.writeToFile(writePath, atomically: true) == false {
return
} else {
let fileURL = NSURL(fileURLWithPath: writePath)
self.documentController = UIDocumentInteractionController(URL: fileURL)
self.documentController.delegate = self
self.documentController.UTI = "com.instagram.exlusivegram"
self.documentController.annotation = NSDictionary(object: captionString, forKey: "InstagramCaption")
self.documentController.presentOpenInMenuFromRect(self.view.frame, inView: self.view, animated: true)
}
} else {
print(" Instagram isn't installed ")
}
}
}
Now this still wont work with iOS 9, so you will have to go to your apps info.plist, add "LSApplicationQueriesSchemes" type: Array, and add the URL Scheme in this case "instagram".
Here try this code
#IBAction func shareContent(sender: UIButton) {
let image = UIImage(named: "imageName")
let objectsToShare: [AnyObject] = [image!]
let activityViewController = UIActivityViewController(
activityItems: objectsToShare,
applicationActivities: nil
)
activityViewController.popoverPresentationController?.sourceView = self.view
activityViewController.excludedActivityTypes = [
UIActivityTypeAirDrop,
UIActivityTypePostToFacebook
]
self.presentViewController(
activityViewController,
animated: true,
completion: nil
)
}

Resources