SMS window wont dismiss objective-C - iphone

Hi I'm trying to make a SMS native extension for adobe AIR.
I Havnt coded in objective-c before but everything works fine except for the fact that the SMS window won't close when pressing send or cancel. Below is the main section of code but ask me if you need any more info. Thanks for reading.
also why is xcode telling me :"Method in protocol not implemented" for the second line ?
#import "SMSComposerHelper.h"
#implementation SMSComposerHelper
//Event name
static NSString *event_name = #"SMS_COMPOSER_EVENT";
-(void) sendSMS:(NSString *)toRecipient
messageBody:(NSString *)messageBody
{
FREDispatchStatusEventAsync(context, (uint8_t*)[event_name UTF8String], (uint8_t*)[#"WILL_SHOW_MAIL_COMPOSER" UTF8String]);
MFMessageComposeViewController *smsComposer = [[MFMessageComposeViewController alloc] init];
smsComposer.messageComposeDelegate = self;
//make string into array
NSArray *recipientArray;
recipientArray = [NSArray arrayWithObjects: toRecipient, nil];
smsComposer.body = messageBody;
smsComposer.recipients = recipientArray;
//show sms composer
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentModalViewController:smsComposer animated:YES];
}
// Dismisses the sms composition interface when users tap Cancel or Send.
-(void) smsComposeController: (MFMessageComposeViewController*)controller didFinishWithResult: (MessageComposeResult)result error:(NSError*)error
{
NSString *event_info = #"";
// Notifies users about errors associated with the interface
switch (result)
{
case MessageComposeResultCancelled:
event_info = #"SMS_CANCELED";
break;
case MessageComposeResultSent:
event_info = #"SMS_SENT";
break;
case MessageComposeResultFailed:
event_info = #"SMS_FAILED";
break;
default:
event_info = #"SMS_UNKNOWN";
break;
}
FREDispatchStatusEventAsync(context, (uint8_t*)[event_name UTF8String], (uint8_t*)[event_info UTF8String]);
FREDispatchStatusEventAsync(context, (uint8_t*)[event_name UTF8String], (uint8_t*)[#"WILL_HIDE_SMS_COMPOSER" UTF8String]);
context = nil;
//hide mail composer
[[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissModalViewControllerAnimated:YES];
}
-(void)setContext:(FREContext)ctx {
context = ctx;
}
#end
RESPONSE :
Omar thankyou so much for your answer and for answering so quickly!
First I tried your solution of using
[controller dismissModalViewControllerAnimated:YES];
but this did nothing so I changed it back.
My header already was :
#interface SMSComposerHelper : NSObject<MFMessageComposeViewControllerDelegate> {
So I decided to focus on fixing the warning.
The warning was solved by changing :
-(void) smsComposeController: (MFMessageComposeViewController*)controller didFinishWithResult: (MessageComposeResult)result error:(NSError*)error
to:
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
I would love to know why this worked ? do you know Omar ?
So I solved the warning but it still didn't dismiss.
So I tried your suggestion again:
[controller dismissModalViewControllerAnimated:YES];
AND IT WORKED !!!!
thanks so much man. You don't know how many hours I was stuck for.
I will be happy to accept your answer.

Instead of
[[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissModalViewControllerAnimated:YES];
write
[controller dismissModalViewControllerAnimated:YES];
Also for the warning
Go to SMSComposerHelper.h
And add the following
#interface SMSComposerHelper : UIViewController<MFMessageComposeViewControllerDelegate>{
instead of
#interface SMSComposerHelper : UIViewController{

Related

After sending an in App email with photo attachment the Email window won't dismiss even when I hit send or cancel

I'm in a bit of trouble, I've spent half a day working onto this issue I have with no major results after all deprecations in iOS6 and other issues. This iOS app, has a send email option when after pushing a button, the app takes a screenshot of my WebView, attaches it to the email and from there, have the normal options to cancel or send the email and return to the app. I made it to the part where the email pops up, and actually 2 issues here: one is that after pressing either cancel or send, the email view won't dismiss, the app is stuck in the email view. And the second issue I have is the image that gets attached is just a tiny icon (blue with an question mark just like it is not recognised or is missing...
Can someone please point me in the right direction as I feel like I'm going crazy. I've researched the net backwards and forwards with no luck. Many similar threads but different issues not exactly related to my issues unfortunately. Sorry, and thanks in advance.
Here is my code:
// in my LiveView.h file
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <MessageUI/MessageUI.h>
#import "CamSetup.h"
#interface LiveView : UIViewController < MFMailComposeViewControllerDelegate , ADBannerViewDelegate >
....
-(IBAction)shotAndSend:(id)sender;
// in my LiveView.m file:
- (void)mailComposer:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
NSLog(#"in didFinishWithResult:");
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"cancelled");
break;
case MFMailComposeResultSaved:
NSLog(#"saved");
break;
case MFMailComposeResultSent:
NSLog(#"sent");
break;
case MFMailComposeResultFailed: {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Error sending mail",#"Error sending mail")
message:[error localizedDescription] delegate:nil
cancelButtonTitle:NSLocalizedString(#"test",#"test")
otherButtonTitles:nil];
[alert show];
break;
}
default: break;
}
[self dismissViewControllerAnimated:NO completion:Nil];
}
-(IBAction)shotAndSend:(id)sender
{
UIGraphicsBeginImageContext(_myWebView.frame.size);
[_myWebView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * imageData = UIImageJPEGRepresentation (image, 2.1);
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController * mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;
[mailComposer addAttachmentData:imageData mimeType:#"image/jpeg" fileName:#"attachment.jpeg"];
[mailComposer setSubject:#"A screenshot from my App"];
[mailComposer setToRecipients:[NSArray arrayWithObjects:#"123#yexample.com", nil]];
[self presentViewController: mailComposer animated:YES completion:NULL];
}
}
Your code isn't working because you have the wrong method. You have:
- (void)mailComposer:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
but it should be:
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
You need a delegate of your view that will dismiss that view for you. The fact that you don't see the log indicate you that you haven't implemented correctly the delegation protocol. Take a look at some example in the apple documentation.

Presenting a modal view from another class (MFMailComposeViewController)

I am trying to create a class who will be responsible to send emails using MFMailComposeViewController so i can use this methods from differences views controls in my app.
This class is called apoio.
In this class have the method bellow.
-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico {
if (![MFMailComposeViewController canSendMail]) {
// show message box for user that SMS cannot be sent
} else {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Dashboard"];
[picker addAttachmentData:_pdfGrafico mimeType:#"application/pdf" fileName:#"grafico.pdf"];
NSString *emailBody = #"Anexando gráfico";
[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
}
}
I have another view controller who calls the apoio method when the user clicks on email button. It is this code bellow
-(IBAction) enviarGraficoPorEmail {
Apoio *apoio = [[Apoio alloc] init];
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}
But i don't know why, the email view doesn't appear. The method is called correct because i debuged and so on.
If i copy the code from apoio method to enviarGraficoPorEmail method, everything works perfect.
But i don't want to do this, beucase ill send emails from others views controller.
What am i doing wrong ??
You could do it a couple of different ways.
Option 1: Pass the calling view controller as a parameter to the class method
-(IBAction) enviarGraficoPorEmail {
Apoio *apoio = [[Apoio alloc] init];
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer] callingController:self];
}
-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
...
[_callingController presentModalViewController:picker animated:YES];
...
}
Option 2: Add a class variable for the calling view controller
-(IBAction) enviarGraficoPorEmail {
Apoio *apoio = [[Apoio alloc] init];
apoio.callingController = self;
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}
-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
...
[callingController presentModalViewController:picker animated:YES];
...
}
Then you'd add callingController to your class as a retain property, initialize it to nil, and release it in dealloc.
Option #1 is probably the better approach for your needs.
Thanks a lot!. It is now working but i still have one problem.
I have the method on my generic class who is supposed to be responsible to hide the mailController.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
case MFMailComposeResultCancelled:
break;
case MFMailComposeResultSaved:
break;
case MFMailComposeResultSent:
// FAILS
[self.parentViewController dismissModalViewControllerAnimated:YES];
break;
case MFMailComposeResultFailed:
break;
default:
break;
}
[self dismissModalViewControllerAnimated:YES];
}
In the method that creates the mailController have the property
picker.mailComposeDelegate = self;
I tried to change to
picker.mailComposeDelegate = _callingController.self;
I set the MFMailComposeViewControllerDelegate on my generic class already.
But it only works when i copy the method didFinishWithResult and put it on the origin controller, what is not my intention, because i want to put all this code on a generic class.
What am i doing wrong ??
Ok, this is an answer to your second question (which you posted as an answer to your first question).
Here's how I would set it all up:
In your calling view controller .h file:
#interface MyViewController : UIViewController <MyMailDelegate> {
Apoio *apoio;
}
In your calling view controller .m file:
-(IBAction) enviarGraficoPorEmail {
apoio = [[Apoio alloc] init];
apoio.callingController = self;
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}
-(void) enviarCompleto {
//do whatever here after send email completes
[apoio release];
}
In your Apoio .h file
#protocol MyMailDelegate
#required
-(void) enviarCompleto;
#end
#interface OfferObject : NSObject {
UIViewController <MyMailDelegate> *callingController;
}
#property (nonatomic, retain) UIViewController <MyMailDelegate> *callingController;
In your Apoio .m file
-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
...
[callingController presentModalViewController:picker animated:YES];
...
}
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
...
}
[callingController dismissModalViewControllerAnimated:YES];
[callingController enviarCompleto];
}
Then don't forget to do this on init:
callingController = nil;
And on dealloc:
[callingController release];
Also, don't forget your most important step: up vote both my answers :)
You need to call [self presentModalViewController:picker animated:YES];
from a UIViewController class then it will show you email composer, you can do this, whenever you call from some view controller you can pass its reference and you can change the above line as this
[callingController presentModalViewController:picker animated:YES];

iPhone In App Email Issue

when I press the sendMail button, it will go to the mail button, but when I hit send or cancel it will not take me back to my application. Any suggestions?
-(IBAction)sendMail {
MFMailComposeViewController *mailComposer = [[[MFMailComposeViewController alloc] init] autorelease] ;
if ([MFMailComposeViewController canSendMail]) {
[mailComposer setToRecipients:nil];
[mailComposer setSubject:nil];
[mailComposer setMessageBody:#"Default text" isHTML:NO];
[self presentModalViewController:mailComposer animated:YES];
}
}
You need to set a delegate (generally the same view controller that presented the MFMailComposeViewController). Then when the user taps the Save or Cancel button the MFMailComposeViewController will call -mailComposeController:didFinishWithResult:error on the delegate. So set yourself as the delegate and define the following method:
#pragma mark -
#pragma mark MessageUI Delegate Methods
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError*)error {
[controller dismissModalViewControllerAnimated:YES];
}
Add the following line below your mail composer initialization
mailComposer.mailComposeDelegate = self;//very important if you want feedbacks on what the user did with your email sheet.
Then implement the delegate method as Kenny suggested. You can use this method to take custom actions.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
{
//Do something, If you need to
}
break;
default:
break;
}
[self dismissModalViewControllerAnimated:YES];
}
Remember to conform to the delegate by adding
#interface YourViewController : UIViewController <MFMailComposeViewControllerDelegate> { }
If you are still having trouble, You may visit the following tutorial where everything nicely explained:
http://blog.mugunthkumar.com/coding/iphone-tutorial-in-app-email/
This wonderful line:
mailComposer.mailComposeDelegate = self;
is what made ​​it happen for days without knowing that was what went wrong.
And do not forget them:
# import <UIKit/UIKit.h>
# import <MessageUI/MessageUI.h>
# import <MessageUI/MFMailComposeViewController.h>
In addition to importing the MessageUI.framework in the project.
Verified in IOS5

Action sheet doesn't display when the MFMailComposeViewController's cancel button is tapped

I'm trying to incorporate MFMailComposeViewController in my app. When I present it modally, the send button works fine and the email is sent, which implies that the result sent to the delegate is right in that case.
Whereas when I tap the cancel button it hangs up the app. The log shows no errors either, just the screen goes dark and everything gets disabled. Apparently, the result is not being passed to the delegate (I checked it through logs). it appears that the
(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
is never called whenever the cancel button is pressed. Probably that's the reason why the actionsheet (Save draft, cancel, delete draft) is not displayed and therefore the app hangs in right there.
I'm using the exact code from Apple's sample apps (MailComposer), it works perfectly there, but somehow fails in mine. :(
Kindly help me if anyone has ever come across the same issue, and successfully resolved it.
My code:
-(IBAction)emailButtonPressed:(id)sender{
Class mailClass = (NSClassFromString(#"MFMailComposeViewController"));
if (mailClass != nil)
{
if ([mailClass canSendMail])
{
[self displayComposerSheet];
}
else
{
[self launchMailAppOnDevice];
}
}
else
{
[self launchMailAppOnDevice];
}
}
#pragma mark -
#pragma mark Compose Mail
-(void)displayComposerSheet
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Ilusiones"];
// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:#"anam#semanticnotion.com"];
[picker setToRecipients:toRecipients];
// Attach a screenshot to the email
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *myData = UIImagePNGRepresentation(viewImage);
[picker addAttachmentData:myData mimeType:#"image/png" fileName:#"viewImage"];
// Fill out the email body text
NSString *emailBody = #"";
[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Result: canceled");
break;
case MFMailComposeResultSaved:
NSLog(#"Result: saved");
break;
case MFMailComposeResultSent:
NSLog( #"Result: sent");
break;
case MFMailComposeResultFailed:
NSLog( #"Result: failed");
break;
default:
NSLog(#"Result: not sent");
break;
}
[self dismissModalViewControllerAnimated:YES];
}
#pragma mark -
#pragma mark Workaround
-(void)launchMailAppOnDevice
{
NSString *recipients = #"mailto:anam#semanticnotion.com.com?cc=second#example.com,third#example.com&subject=illusions!";
NSString *body = #"&body=xyz";
NSString *email = [NSString stringWithFormat:#"%#%#", recipients, body];
email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:email]];
}
Method
(void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError*)error
is never called because you don't press any UIActionSheet button after cancelling, as it doesn't show on screen.
The reason this is happening is that the UIActionSheet appears off-screen. If you check the debug log you'll probably see a message saying Presenting action sheet clipped by its superview. Some controls might not respond to touches. On iPhone try -[UIActionSheet showFromTabBar:] or -[UIActionSheet showFromToolbar:] instead of -[UIActionSheet showInView:]."
That's why you see your view getting darker, but no UIActionSheet appears.
In my case, the problem was that my app is universal, but for some reason there was only one MainWindow.xib, and it was larger than the iPhone screen size (it was, in fact, the iPad screen size).
The solution is to create another MainWindow-iPhone.xib with the right dimensions and change the Info.plist entries called Main nib file base (iPad) and Main nib file base (iPhone) so that they point to the right file. Problem solved!
Hope it helps.
I had the same problem,commented out '[picker release];', and it worked fine! Explanation? I have none.
Msoler has it right, teh action sheet is displayed off-screen.
The MFMailComposeViewController display the action-sheet at x:y 0:0, so you have to make sure teh calling controller frame is at 0:0. I had a similar issue when I tried to display the MFMailComposeViewController from a view that was embedded in a scroll view.
I have implemented the same code . It works absolutely fine. When you click on the delete draft button,didFinishWithResult method is called and the mail is cancelled.
Be sure that you use the correct method,
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
I had a some what similar method implemented which was never called. I have no idea what I exactly had but the compiler did not give me a warning or error message.
Just in case anybody else makes the same mistake as I did... I implemented the mailComposeController:didFinishWithResult:error: method in my Swift code. It worked for a while but after several refactorings I noticed that it was suddenly not being called anymore. Eventually I noticed that the method had taken this form in my code:
private func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
So, as you can see I was a little bit too eager about privatizing my methods: Since the method is marked #optional in the MFMailComposeViewControllerDelegate you do not have to implement it. And while I actually had implemented it, the private modifier from there on hid the implementation - thus, from outside the file it seemed that the method was actually not implemented, at all! However, since the method was optional, the compiler did not complain...
To conclude: Do not mark optional delegate with the modifier private.
I have been wondering ever since learning Swift why there are no optional methods anymore - now I might have understood ;-).

iPhone: How to Close MFMailComposeViewController?

I'm having difficulties closing an email message that I have raised.
The email opens nicely, but once it is opened it will not close as the mailComposeController:mailer didFinishWithResult:result error:error handler never gets invoked.
As far as I can tell I have all the bits in place to be able to do this.
Anyone any ideas of what I can look at?
Here is how I raise the email:
-(IBAction)emailButtonPressed
{
NSString *text = #"My Email Text";
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.delegate = self;
[mailer setSubject:#"Note"];
[mailer setMessageBody:text isHTML:NO];
[self presentModalViewController:mailer animated:YES];
[mailer release];
}
and later in the class I have this code to handle the close (but it never gets called):
-(void)mailComposeController:(MFMailComposeViewController *)mailer didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
[self becomeFirstResponder];
[mailer dismissModalViewControllerAnimated:YES];
}
My header file is defined as:
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>
#interface myViewController : UIViewController <UIActionSheetDelegate, UIAlertViewDelegate, MFMailComposeViewControllerDelegate, UINavigationControllerDelegate>
Thanks
Iphaaw
You are setting the delegate wrong, the delegate property in MFMailComposeViewController is called mailComposeDelegate, so it should be:
mailer.mailComposeDelegate = self;
Another possible error I can see is calling dismissModalViewControllerAnimated: on mailer - you should send this message to the view controller who presented the mail interface - self in this case:
[self dismissModalViewControllerAnimated:YES];
I wrote "possible error" because it might actually work if iOS routes the message through responder chain, anyway - the documentation says it should be send to presenter.