Attaching an email within app? - ios

So I have had this problem for sometime and just cant get it working! I have been building a survey app that users simply enter information in and its saved to a csv file. Im now at the stage where I need to attached the csv file within the app to an email address...
I have the code as follows, it should work but for some reason is attaching a 'blank' csv file instead of the one with the data in. Im guessing it must be something to do with the file path however cant get it working!!
- (IBAction)send:(id)sender {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedFilePath = [documentsDirectory stringByAppendingPathComponent:#"result‌s.csv"];
NSData *csvData = [NSData dataWithContentsOfFile:savedFilePath];
MFMailComposeViewController *mailcomposer = [[MFMailComposeViewController alloc] init];
[mailcomposer addAttachmentData:csvData mimeType:#"text/csv" fileName:#"results.csv"];
[mailcomposer setToRecipients:#[#"gpsflighttrial#gcap.eu"]];
[mailcomposer setSubject:self.subject.text];
[mailcomposer setMessageBody:self.message.text isHTML:NO];
}
UPDATE:
So I just tested this on my new i-phone and there is no attachment when the email is delivered? Its there in the mail app and in the simulator, however when the message is received the attachment has gone? Can anyone help??

I've just tried your code and it seems ok. Add this code to see what you actually have in that csv file.
NSString *strData = [[NSString alloc]initWithData:csvData encoding:NSUTF8StringEncoding];
NSLog(#"Output %#",strData);

Try to check csvData contents, it's probably empty.

Related

Generate a ppt file with byte array/NSData, in objective c?

I have a NSData value, generated from a byte array response. Now I need to save this as a .ppt file in iPhone/iPad, I learned from this link that there is no way to directly do it.
I already tried saving it as a PDF first, but failed in that too, since I'm unable to reproduce the charts from the nsdata.
Now is there another way to get this done other than sending the file through mail associated to the device?
Please do give out only the ways by which I can carry this out in the background without the help of the user? Any help will be appreciated.Thanks
I got it working, tried a lot but nothing worked and finally ran into some random code blocks, using which I got this wonderful piece of code,
//--------------------------------------------------------------------------------generating input URL
NSString *urlAddress = #"url containing the pdf data";
NSURL *theRessourcesURL = [NSURL URLWithString:urlAddress];
//--------------------------------------------------------------------------------defining file location details & writing a ppt file with a name "new.ppt"
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathFloder = [[NSString alloc] initWithString:[NSString stringWithFormat:#"%#",#"new.ppt"]];
NSString *defaultDBPath = [documentsDirectory stringByAppendingPathComponent:pathFloder];
NSData *tmp = [NSData dataWithContentsOfURL:theRessourcesURL];
[tmp writeToFile:defaultDBPath atomically:YES];

CSV to NSString to NSData with Hebrew text issue

I'm creating a CSV file from CoreData using CHCSVWriter, so far so good and the file is creating perfectly. My problem is when i'm trying to send the CSV file that i've created i'm running in some issues, I open the CSV file with Excel and instead of Hebrew text I see gibberish.
While using NSLog to print the result of the CSV string, I see the Hebrew just fine. Even after converting it from NSString to NSData and back again.
This is what I get:
יוסי צפר
This is my code:
- (void)createCSV
{
CHCSVWriter *writer = [[CHCSVWriter alloc] initForWritingToCSVFile:[self csvFilePath]];
for (EWDBUsers *user in self.users)
{
[writer writeField:user.name];
[writer writeField:user.company];
[writer writeField:user.email];
[writer writeField:user.telephone];
[writer finishLine];
}
[writer closeStream];
}
- (NSString*)csvFilePath
{
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = #"users.csv";
return [documentsDirectory stringByAppendingPathComponent:filename];
}
- (void)showMailComposerController
{
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController* controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Users List"];
[controller setMessageBody:#"Attachment." isHTML:NO];
NSError *error;
NSString *csvFileString = [NSString stringWithContentsOfFile:[self csvFilePath] encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#", csvFileString);
NSData *csv = [csvFileString dataUsingEncoding:[NSString defaultCStringEncoding]];
[controller addAttachmentData:csv mimeType:#"text/cvs" fileName:#"users.csv"];
if (controller) {
[self presentModalViewController:controller animated:YES];
}
} else {
return;
}
}
Can someone please tell me what am I doing wrong?
Thanks in advance.
You're seeing gibberish because you're converting Unicode to ASCII. [csvFileString dataUsingEncoding:[NSString defaultCStringEncoding]] should be [csvFileString dataUsingEncoding:NSUTF8StringEncoding].
Also, mimeType:#"text/cvs" should be mimeType:#"text/csv".
EDIT: The issue seems to be Excel. Opening the received CSV file in TextEdit displays just fine.
My solution is adding BOM chars at start to solve a bug in Excel when try to open CSV files and save the UTF-8 Encoding.
cvsStringFile = [[NSString alloc] initWithFormat:#"\357\273\277%#", cvsStringFile];
NSData *myXLSData = [cvsStringFile dataUsingEncoding:NSUTF8StringEncoding];
[picker addAttachmentData:myXLSData mimeType:#"text/csv;charset=utf-8" fileName:#"Report.csv"];
I suspect, there is an encoding issue. You are sending generated file with an invalid MIME type: text/cvs.
I would use text/plain with an explicit charset parameter, e.g.
text/plain; charset=utf-8
and explicitly encode the csv string into an NSData using that encoding (e.g. NSUTF8StringEncoding).
Edit:
Actually, there is a MIME type text/csv
So, you may also use: text/csv; charset=utf-8

How to load app with local data and subsequently update it when online.

Right now I have an app that successfully parses JSON from my website. So whenever there is no internet connection, my app crashes. Now I am trying to make it so that when the app is loaded with no internet connection, it will show the data that was shown previously. What would be the best way to do this?
I read this article but I don't know how to embed a JSON file into my app bundle. Could someone explain how to do this?
Thanks in advance!
The best way is:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"YourParsedJSON.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (noInternet){
if ([fileManager fileExistsAtPath: path]){
// if this is true, you have a saved version of your JSON
YourArray = [[NSMutableArray alloc] initWithContentsOfFile: path];
// or
YourDict = [[NSMutableArray alloc] initWithContentsOfFile: path];
}
else{
// first time the app is running, and no internet, no json, inform user about this
}
}
else{
// make an array or dictionary ( what is your JSON )
// response can be a NSDictionary or NSArray
// YourArray = parsedJSON or YourDict = parsedJSON
[YourArray writeToFile:path atomically:YES];
//or
[YourDictionary writeToFile:path atomically:YES];
}
I hope it helps !
Use Apple Reachability sample code to check if your app is able to establish connection to your server.
On first successful request-response, parse the JSON and cache it to disk as a .plist file. This will save you parsing the stored response again. A parsed JSON response can be a NSDictionary or NSArray. Use the writeToFile:atomically: API to write it to disk.
On subsequent request, if reachability fails, i.e. no network connectivity, read the cached response from disk. You need to decide the cache duration and update the plist when a fresh response is fetched.
Hope that helps!
EDIT:
I think I did not understand the question completely. Thanks Xman, for pointing it out. What I would have done in this case is - save the last loaded JSON file to my bundle and use it for displaying information while querying the server and loading updates in the background.
The flow should be like this:
Parse and display data using local JSON file. (Assuming there is local copy of JSON file)
Query the server for latest data.
Upon receiving response, update the bundle with the latest JSON file.
Then, do step 1. In case there is no JSON file, just start from step 2. If there is a Network error display the appropriate information.
This SO question answers how to handle Network connections in iOS: How to check for an active Internet connection on iOS or OSX?
Saving file locally:
Assuming you have the unparsed JSON data in a NSString (responseString) do the following:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, #"latest_json.json"];
NSError *error;
[jsonString_ writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#", error)
Reading file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, #"latest_json.json"];
NSString *jsonString_ = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
Previous Answer
Embedding JSON file is similar to embedding any resource into your project. The following method shows you how I added an XML file and accessed it in my app.
Drag and drop your JSON/XML file to your resources group/folder in your XCode window. If you don't have the Resouces folder, it is better you create it. Then in your code do this:
NSString* filePath_ = [[NSBundle mainBundle] pathForResource:#"fileName" ofType:#"json"];
NSString *jsonString = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error: NULL];
the variable jsonstring contails the JSON information. It is upto you how you would like to parse it.

iOS - attaching a PDF file: PDF ok in simulator folder, but corrupted when attached to email on device

Hopefully the title made sense. Here's my situation.
I have one PDF created in Pages then exported as a PDF. I then create another PDF within the app. I create the PDF file with this code:
- (void)makePDF:(NSString*)fileName :(NSDictionary*)dictResults
{
pageSize = CGSizeMake(612, 792);
_strPDFJustCreated = fileName;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];
[self generatePdfWithFilePath:pdfFileName:dictResults];
}
- (void)generatePdfWithFilePath:(NSString *)thefilePath :(NSDictionary*)dictResults
{
UIGraphicsBeginPDFContextToFile(thefilePath, CGRectZero, nil);
BOOL done = NO;
do {
...whole lot of coding goodness
done = YES;
} while (!done);
// Close the PDF context and write the contents out.
UIGraphicsEndPDFContext();
}
Both files are attached to the email message with this code:
/**********Attach PDF Files**************/
//get path to pdf file
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* pdfFilePath = [documentsDirectory stringByAppendingPathComponent:strPDFFileName];
//convert pdf file to NSData
NSData* pdfData = [NSData dataWithContentsOfFile:pdfFilePath];
//attach the pdf file
[mailViewController addAttachmentData:pdfData mimeType:#"application/pdf" fileName:strPDFFileName];
//get path to pdf file
NSString* pdf2FilePath = [documentsDirectory stringByAppendingPathComponent:#"OER_MarketingContent.pdf"];
//convert pdf file to NSData
NSData* pdf2Data = [NSData dataWithContentsOfFile:pdf2FilePath];
//attach the pdf file
[mailViewController addAttachmentData:pdf2Data mimeType:#"application/pdf" fileName:#"OER_MarketingContent.pdf"];
[self presentViewController:mailViewController animated:YES completion:NULL];
When I take a peak inside the app folder within the iPhone Simulator folder the pdf files are there, they are recognized by the OS as PDF files and I can open and read them. However, when I get an email message delivered (and don't laugh but we use Lotus Notes), I cannot preview the files I can't an error message saying there is no filter available, when I opt to open it (in Preview) it just hangs.
I use the same code in other apps with no problems. My guess then is that I am doing something different somewhere in my code. I can't see anything obvious so my question would be is there a way to test say NSData for success/failure prior to attaching the file or testing it post attachment but pre email?
Thanks
Don't use UIGraphicsBeginPDFContextToFile(thefilePath, CGRectZero, nil);. Instead, use: NSData * pdfData = [NSData dataWithContentsOfFile:pdfFileName];.
So, the whole thing should end up looking like:
NSString *fileName = #"Demo.pdf";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];
[self generatePdfWithFilePath:pdfFileName];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setToRecipients:[NSArray arrayWithObject:#"email#email.com"]];
[controller setSubject:#"PDFTEST"];
[controller setMessageBody:#"Your text here" isHTML:NO];
NSData * pdfData = [NSData dataWithContentsOfFile:pdfFileName];
NSString *testFileName = [NSString stringWithFormat:#"PDFNAME"];
[controller addAttachmentData:pdfData mimeType:#"application/pdf" fileName:testFileName];
[self presentModalViewController:controller animated:YES];
This worked for me. Let me know if you have any more questions or if this is unclear. Thanks!

Launching MFMailComposeViewController cuts off recipient text

I am using Apple's sample code for the MessageUI and MFMailComposeViewControllerDelegate, and mostly it works great. But for some reason when I implement it, the text in the recipient fields appears out of alignment with the field labels, and you can only see half of the cursor and half of the text while typing. Once you've typed the addresses and exited the field, the text is completely visible, though still out of alignment with the labels. I have looked at other apps' implementations of the MessageUI, and they do not seem to have this problem. has anyone seen this problem and found a solution?
Below is code:
-(void)displayComposerSheet
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Data"];
// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:#"email#example.com"];
[picker setToRecipients:toRecipients];
// Attach an attachment to the email
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *csvFile = [documentsDirectory stringByAppendingPathComponent:#"myFile.csv"];
NSData *myData = [NSData dataWithContentsOfFile:csvFile];
NSString *filename = #"myFile.csv";
[picker addAttachmentData:myData mimeType:#"text/csv" fileName:filename];
// Fill out the email body text
NSString *emailBody = #"Attached is the data";
[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
}
The problem occurs in both the simulator and on device.
Probably, you've got a custom UITextField in your app and have some custom code in - (CGRect)textRectForBounds:(CGRect)bounds. If you'd like to have some category for UITextField class, try to put your specific code directly to the class where you using that instead of using category, which affects all textfields in your app, even in MFMailComposeViewController

Resources