In my app, it is very important to know whether SMS has been sent or not. For checking, I am using this delegate method:
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result{
switch (result) {
case MessageComposeResultCancelled: {
[NSThread detachNewThreadSelector:#selector(SMScancelled) toTarget:self withObject:nil];
}
break;
case MessageComposeResultSent: {
[NSThread detachNewThreadSelector:#selector(SMSsent) toTarget:self withObject:nil];
}
break;
case MessageComposeResultFailed: {
[NSThread detachNewThreadSelector:#selector(SMSfailed) toTarget:self withObject:nil];
}
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:nil];
}
My problem is, that when testing, I turn on Airplane mode in settings (to test what will happen) and then I am trying to send SMS (using my app). Naturally, iOS fails to send it and system informs me about that. In message app, it is also shown, that I have failed to send it. But delegate method still returns MessageComposeResultSent instead of MessageComposeResultFailed. This situation also happens when I test on another phone that has no SIM card.
I am testing this on iOS 7 and iOS 8.
In documentation, there is written, that MessageComposeResultSent means "The user successfully queued or sent the message". This means, behaviour I am expecting is correct.
So how to know, whether my last SMS has been succesfully sent, or that sending has failed?
You can verify if the device is allowed to send text message by using the canSendText method of the MFMessageComposeViewController.
Add this below code when you care sending the message (This method detects of your device does not support SMS)
if(![MFMessageComposeViewController canSendText]) {
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Your device doesn't support SMS!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[warningAlert show];
return;
}
You can check Message failed by using delegate method of MFMessageComposeViewController
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult) result
{
switch (result) {
case MessageComposeResultCancelled:
break;
case MessageComposeResultFailed:
{
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Failed to send SMS!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[warningAlert show];
break;
}
case MessageComposeResultSent:
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Related
The MFMailComposeViewController is dismissing immediately when appear
- (IBAction)btnContactPressed:(id)sender
{
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"Feedback"];
NSArray *toRecipients = [NSArray arrayWithObjects:#"salimullah240#gmail.com", nil];
[mailer setToRecipients:toRecipients];
[self presentViewController:mailer animated:YES completion:nil];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Failure"
message:#"Your device doesn't support the composer sheet"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Mail cancelled: you cancelled the operation and no email message was queued.");
break;
case MFMailComposeResultSaved:
NSLog(#"Mail saved: you saved the email message in the drafts folder.");
break;
case MFMailComposeResultSent:
NSLog(#"Mail send: the email message is queued in the outbox. It is ready to send.");
break;
case MFMailComposeResultFailed:
NSLog(#"Mail failed: the email message was not saved or queued, possibly due to an error.");
break;
default:
NSLog(#"Mail not sent.");
break;
}
// Remove the mail view
[self dismissViewControllerAnimated:YES completion:nil];
}
Your code is correct. I tried and worked fine. The MFMailComposeViewController component can't be tested in the iOS simulator only in a device.
If you look this Thread in Apple Developer Forums the problem has a ticket in Apple Bug Report but still without any fix.
Also, just make sure you are importing:
#import <MessageUI/MFMailComposeViewController.h>
and adding the delegate:
#interface ViewController () <MFMailComposeViewControllerDelegate>
Only the email-subject is getting set to "Test mail" and recipients remain empty. MailController opens for a while and gives the alert as "Message Cancelled".
Anyone please help me out!
- (IBAction)sendEmail:(id)sender { //This is a button to send E-mail
mailController=[[MFMailComposeViewController alloc]init];
NSString *emailBody = #"Test mail from Fortune";
[mailController setToRecipients:[NSArray arrayWithObjects:#"hi#fortune.com",#"hello#fortune.com", nil]];
[mailController setCcRecipients:#[#"gthg65#gmail.com"]];
[mailController setBccRecipients:#[#"resumes#fortune.com"]];
[mailController setMessageBody:emailBody isHTML:NO];
[mailController setSubject:#"Test mail "];
mailController.mailComposeDelegate=self;
[self presentViewController:mailController animated:YES completion:nil];
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
NSString *messageResult;
if (error!=nil)
{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Mail Error" message:[error localizedDescription] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
else{
switch (result) {
case MFMailComposeResultCancelled:
messageResult=#"Mail Cancelled";
break;
case MFMailComposeResultFailed:
messageResult=#"Mail Failed";
break;
case MFMailComposeResultSaved:
messageResult=#"Mail Saved";
break;
case MFMailComposeResultSent:
messageResult=#"Mail Sent";
break;
default:
break;
}
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Mail Result" message:messageResult delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Works on a test device. Also Apple recently changed their developer account memberships and you can register for a free apple developer account and run the app on a test device that way.
I am using AFNetworking 2.0 to make network calls. I am using the code below for reachability. My problem is that the "Not connected" alert always shows when I open the app. It seems like it takes a while for the app to get connected to the network and that lag is causing the alert to pop up. Is there any way to fix this? I don't want the "Not connected" alert popping up every time and confusing users.
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));
switch (status) {
{case AFNetworkReachabilityStatusNotReachable:
NSLog(#"No Internet Connection");
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Not connected"
message:#"You have no network connection"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
}
break;
{case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(#"WIFI");
}
break;
{case AFNetworkReachabilityStatusReachableViaWWAN:
NSLog(#"4G");
}
break;
default:
NSLog(#"Unkown network status");
break;
}
}];
[[AFNetworkReachabilityManager sharedManager]startMonitoring];
if ([[AFNetworkReachabilityManager sharedManager] isReachable] == NO) {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Not connected"
message:#"You're not connected to the internet. Please connect via WiFi or data plan"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
//this shows all the time - why?
}
put this code in your AppDelegate in this method didFinishLaunchingWithOptions. it will display message only one time.
internetReachableFoo = [Reachability reachabilityWithHostname:#"www.google.com"];
internetReachableFoo.reachableBlock = ^(Reachability*reach)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Yayyy, we have the interwebs!");
});
};
internetReachableFoo.unreachableBlock = ^(Reachability*reach)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alrt=[[UIAlertView alloc]initWithTitle:#"Error" message:#"No Internet Connection\nPlease Check The Connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alrt show];
});
};
[internetReachableFoo startNotifier];
Because AFNetworkReachabilityManager refreshs its status by notification.
So when you call
[AFNetworkReachabilityManager sharedManager] isReachable]
after the startMonitoring immediately,the status is not get ready.
I've developed an app that allows the user to text contacts that they add in the app. The problem I'm having is it seems that if the user already exists in the person's native iOS address book, the text will send no problem. But if the contact exists only within the app, the text will not go through. Has anyone else experienced something like this before?
EDIT: Code below
if([MFMessageComposeViewController canSendText])
{
controller.body = #"";
controller.recipients = arrayContactMobileStrings;
controller.messageComposeDelegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Message not sent", #"") message:NSLocalizedString(#"Error sending message", #"")
delegate:self cancelButtonTitle:NSLocalizedString(#"OK", #"") otherButtonTitles: nil];
switch (result)
{
case MessageComposeResultCancelled:
[alert show];
break;
case MessageComposeResultFailed:
[alert show];
break;
case MessageComposeResultSent:
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Hi I am using MFMessageComposeViewController for messaging in an iPhone app.
As this is an iPhone app it also supports iPod. And when clicking on the message button the app crashes as messaging is not available on iPod. So is there a way to check whether the device is an iPod so that i can hide the message button so that the user may not click on message in iPod and crash.
This is the code I have used for messaging.
- (IBAction)Message:(id)sender
{
MFMessageComposeViewController *messaging=[[MFMessageComposeViewController alloc]init];
messaging.messageComposeDelegate=self;
[messaging setBody:#"Will of the People""\n""http://bit.ly/1gZhZye"];
[self presentViewController:messaging animated:YES completion:nil];
}
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissViewControllerAnimated:YES completion:^{UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Done" message:nil delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
}];
}
And this seems to be working fine in iPhone. I need a way to disable this button when the user is using iPod.
You can use the canSendText class method for doing this:
- (IBAction)Message:(id)sender
{
if ([MFMessageComposeViewController canSendText])
{
MFMessageComposeViewController *messaging=[[MFMessageComposeViewController alloc]init];
messaging.messageComposeDelegate=self;
[messaging setBody:#"Will of the People""\n""http://bit.ly/1gZhZye"];
[self presentViewController:messaging animated:YES completion:nil];
}
}
Reference :
canSendText
Returns a Boolean value indicating whether the current device is
capable of sending text messages.
+ (BOOL)canSendText
Return Value
YES if the device can send text messages or NO if it cannot.
Discussion
Always call this method before attempting to present the message
compose view controller. A device may be unable to send messages if it
does not support messaging or if it is not currently configured to
send messages. This method applies only to the ability to send text
messages via iMessage, SMS, and MMS.
To be notified of changes in the availability of sending text
messages, register as an observer of the
MFMessageComposeViewControllerTextMessageAvailabilityDidChangeNotification
notification. Availability
Available in iOS 4.0 and later.
Declared In MFMessageComposeViewController.h
There's a method on MFMEssageComposeViewController:
if ([MFMessageComposeViewController canSendText]) {
}
else {
NSLog(#"Cannot send text");
}
NSString *deviceType = [UIDevice currentDevice].model;
if ([deviceType hasPrefix:#"iPod"])
{
//It's iPod;
//Disable button
}
First detect device by using following way and if device does not support messenger than show alert.
Form here you can get more idea about different device detection :
Determine device (iPhone, iPod Touch) with iPhone SDK
- (IBAction)Message:(id)sender
{
NSString *deviceType = [UIDevice currentDevice].model;
if([deviceType isEqualToString:#"iPod Touch 5G"]) {
// here your alert view to show msg
} else {
if ([MFMessageComposeViewController canSendText])
{
MFMessageComposeViewController *messaging=[[MFMessageComposeViewController alloc]init];
messaging.messageComposeDelegate=self;
[messaging setBody:#"Will of the People""\n""http://bit.ly/1gZhZye"];
[self presentViewController:messaging animated:YES completion:nil];
}
}
}
You can use the UIDevice class to check the device type
NSString *deviceType = [UIDevice currentDevice].model;
if([deviceType hasPrefix:#"iPod"])
// it's an iPod
or you can use [MFMessageComposeViewController canSendText] to check the message can be send from the device or not
-(IBAction)btnByEmailPressed:(id)sender
{
if ([MFMailComposeViewController canSendMail] == NO)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"This device is not able to send mail or Email account is not configured." delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
return;
}
else
{
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setTitle:#"Invitation"];
[controller setSubject:#"My Subject"];
[controller setMessageBody:#"Your Text" isHTML:YES];
[self presentViewController:controller animated:YES completion:nil];
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
[self becomeFirstResponder];
NSString *strMailResult;
switch (result)
{
case MFMailComposeResultCancelled:
strMailResult = NSLocalizedString(#"E-Mail Cancelled",#"");
break;
case MFMailComposeResultSaved:
strMailResult = NSLocalizedString(#"E-Mail Saved",#"");
break;
case MFMailComposeResultSent:
strMailResult = NSLocalizedString(#"E-Mail Sent",#"");
break;
case MFMailComposeResultFailed:
strMailResult = NSLocalizedString(#"E-Mail Failed",#"");
break;
default:
strMailResult = NSLocalizedString(#"E-Mail Not Sent",#"");
break;
}
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"STEP-BY-STEP-STORY",#"") message:strMailResult delegate:self cancelButtonTitle:NSLocalizedString(#"OK",#"") otherButtonTitles:nil];
[alertView show];
[self dismissViewControllerAnimated:YES completion:nil];
}