How to add email to an existing iOS app - ios

I created an app based on the "Tabster" sample code from Apple. The app runs great, but I want to add email to it. I created an email app. and have tried every approach I can think of, learn from a tutorial, or read, but it continually crashes. I posed the question on the Apple Dev. forum and several responses were to simply "copy the files over to the existing app. and you should be good." Obviously its not this simple. I have added the MessageUI Framework and have tried copying the files in many different ways and Im am still stuck. Its Friday and this one problem has held me up since Monday. I guess the first part is the fact that there are 2 main.m files and I have tried combining them, I have tried renaming the mail's main.m file to emailmain.m. I dont know what else to try.
Its amazing to me that all of the documentation and all of the tutorials out there about creating email within an iOS app all start off with creating a new application. What am I missing? How do I add email into a fully functioning app. I would appreciate any guidance, links to literature, or tutorials on the subject.
Any help I can get on this will be tremendously appreciated. There are several other types of things I would like to add on to it, but I cant even get email implemented into it!
Thank you for help you can provide.
John

This is the method I use all the time. It should be able to be added to ANY UIViewController simple and cleanly.
Import your framework:
#import <MessageUI/MessageUI.h>
Make sure you include your delegate in the interface:
#interface MyViewController : UIViewController <MFMailComposeViewControllerDelegate>
Then in your implementation add this method or a variation if you need it to be an IBAction or something like that:
- (void)sendEmail
{
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *email = [[MFMailComposeViewController alloc] init];
email.mailComposeDelegate = self;
[email setSubject:#"My Email Subject"];
[email setMessageBody:#"My message body." isHTML:NO];
[self presentModalViewController:email animated:YES];
} else {
UIAlertView *emailAlert = [[UIAlertView alloc] initWithTitle:#"Email Failure" message:#"Your device is not configured to send email" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[emailAlert show];
}
}
You can call this method on button click or anything you want. It will pull up an email composer view where your user can hit send.

You need to import the MessageUI Framework. Where ever you want to use it import it in the corresponding .h file and set up the MFMailComposeViewControllerDelegate.
#import <MessageUI/MessageUI.h>
#interface ViewController : UIViewController <MFMailComposeViewControllerDelegate>
Then when you want to send a message use the following code in the .m file:
MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.mailComposeDelegate = self;
// Optional Configuration Parameters to make life easier for the user
[mailViewController setSubject:subjectString];
[mailViewController setMessageBody:messageString isHTML:YES];
[mailViewController setToRecipients:recipientsArray];
// Present the VIew Controller and clean up after ourselves
[self presentModalViewController:mailViewController animated:YES];
[mailViewController release];
Add the appropriate delegate method, you can use it to dismiss the controller once the email is sent:
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[self dismissModalViewControllerAnimated:YES];
}

Here Is asample code to create email with an image as attachment .you can modify it according to your needs.
-(void)createEmail
{
NSMutableString *emailBody = [[[NSMutableString alloc] initWithString:#"<html><body>"] retain];
[emailBody appendString:#"<p>Some email body text can go here</p>"];
UIImage *emailImage = [UIImage imageNamed:#"myImageName.png"];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(emailImage)];
NSString *base64String = [imageData base64EncodedString];
[emailBody appendString:[NSString stringWithFormat:#"<p><b><img src='data:image/png;base64,%#'></b></p>",base64String]];
[emailBody appendString:#"</body></html>"];
NSLog(#"%#",emailBody);
//mail composer window
MFMailComposeViewController *emailDialog = [[MFMailComposeViewController alloc] init];
emailDialog.mailComposeDelegate = self;
[emailDialog setSubject:#"My Inline Image Document"];
[emailDialog setMessageBody:emailBody isHTML:YES];
[self presentModalViewController:emailDialog animated:YES];
[emailDialog release];
[emailBody release];
}

Related

Access view controller without re-initializing

Essentially I'm working with 3 view controllers.
Main view which starts a download. (Webview based which passes the download).
Modal download controller. (Tab based).
Downloader (HCDownload).
In the main view my download gets passed like so:
//Fire download
[activeDL downloadURL:fileURL userInfo:nil];
[self presentViewController:vc animated:YES completion:nil];
activeDL is initialized in viewDidLoad:
activeDL = [[HCDownloadViewController alloc] init];
If I removed the presentViewController, it still downloads, which is fine. Then i tap my Downloads button, it brings up the controller which defines the tabs like so:
center = [[CenterViewController alloc] init];
activeDL = [[HCDownloadViewController alloc] init];
completedDL = [[DownloadsViewController alloc] init];
activeDL.tabBarItem = [[UITabBarItem alloc] initWithTitle:#"Active Downloads"
image:nil //[UIImage imageNamed:#"view1"]
tag:1];
completedDL.tabBarItem = [[UITabBarItem alloc] initWithTitle:#"Completed Downloads"
image:nil //[UIImage imageNamed:#"view3"]
tag:2];
[self setViewControllers:[NSArray arrayWithObjects:activeDL, completedDL, nil]];
However, it is not passing the current active download. I don't know if it's a initialization problem, or my tab issue of showing the current download.
From his github, he suggests to get the current number of downloads is to call: dlvc.numberOfDownloads which for me would be
[activeDL numberOfDownloads].
I call this in the the Downloader viewWillAppear but nothing shows.
Does anybody has any suggestions or have worked with this controller?
Any help would be appreciated.
When you call:
activeDL = [[HCDownloadViewController alloc] init];
You are creating a new download controller, which has its own internal downloads array. This library, as written, has no way to pass this information from one HCDownloadViewController object to another.
Tying downloads to VC's like this will cause problems -- I recommend you rewrite this code to split that apart.
To hack around it, try to create just one HCDownloadViewController object and pass it around.
Ok so with the last comment of the other answer, "Make activeDL a member variable instead of a local variable.", got me Googling and with some tinkering and bug fixing along the way I managed to get it all up and running perfect.
I declared it all in my AppDelegate.
AppDelegate.h
#interface SharedDownloader : HCDownloadViewController <HCDownloadViewControllerDelegate>
+ (id)downloadingView;
#end
AppDelegate.m
static HCDownloadViewController *active;
#implementation SharedDownloader
+ (id)downloadingView {
if (active == nil)
active = [[HCDownloadViewController alloc] init];
return active;
}
#end
Calling to the class for downloading in my main view controller:
-(id)init{
activeDL = [SharedDownloader downloadingView];
return self;
}
//Spot where I fire the download
if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
//More code here
[activeDL downloadURL:fileURL userInfo:nil];
}
Lastly in my tab bar controller:
-(id)init {
activeDL = [SharedDownloader downloadingView];
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
activeDL.tabBarItem = [[UITabBarItem alloc] initWithTitle:#"Active Downloads" image:nil] tag:2];
}
I believe that's all of it. In any case, thanks to Lou Franco for pointing me in the right direction.

ios7 blank screen from framework

I have a framework that creates some views, the app that uses the framework calls a method from it and pass in the current view controller, the framework then calls presentModalViewController to display a view.
It was working just fine with iOS 6.1 SDK but when I updated to Xcode 5 and iOS 7 SDK I don't see the modal view anymore, instead all I get is a blank screen.
EDIT
Heres some code:
The Framework is called "testityi"
testityi.m
#import "TestViewController.h"
#implementation testitiy
- (NSString*) sayHi : (NSString*) name {
return [NSString stringWithFormat:#"Hello %#", name];
}
- (void) displayView:(UIViewController *)parentController {
TestViewController* controller = [[TestViewController alloc] init];
[parentController presentViewController:controller animated:YES completion:nil];
}
TestViewController is simply a view with a label that says "View from framework"
The framework itself works fine, calling sayHi method works just fine.
The third party app has a view with a label and a button which calls sayHi method and then displayView method, heres the view controller code:
MainViewController.m
- (IBAction)buttonPressed:(id)sender {
testitiy* framework = [[testitiy alloc] init];
NSString* msg = [NSString stringWithFormat:#"Calling sayHi method on framework...\n result: %#", [framework sayHi:#"John"]];
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"sayHi method call" message:msg delegate:self cancelButtonTitle:#"Ok, show me the view" otherButtonTitles:nil, nil];
[alert show];
}
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == [alertView cancelButtonIndex]) {
testitiy* framework = [[testitiy alloc] init];
[framework displayView:self];
}
}
The alert button action is also working correctly, I added a NSLog before and its working.
After clicking the alert button a view is presented but instead of containing the label "View from framework" I get a blank screen.
You can see the code on Github
EDIT 2
I got it... I wasn't calling initWithBundle on the ViewController from the framework, I added the a custom init method that calls:
framework: TestViewController.m
+ (NSBundle *)frameworkBundle {
static NSBundle* frameworkBundle = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
NSString* mainBundlePath = [[NSBundle mainBundle] resourcePath];
NSString* frameworkBundlePath = [mainBundlePath stringByAppendingPathComponent:#"testity.bundle"];
frameworkBundle = [NSBundle bundleWithPath:frameworkBundlePath];
});
return frameworkBundle;
}
- (id) initWithFramework {
NSBundle* bundle = [[self class] frameworkBundle];
self = [super initWithNibName:#"TestViewController" bundle: bundle];
return self;
}
And changed testitiy.m
- (void) displayView:(UIViewController *)parentController {
TestViewController* controller = [[TestViewController alloc] initWithFramework];
[parentController presentViewController:controller animated:YES completion:nil];
//[parentController.navigationController pushViewController:controller animated:YES];
}
And now its working...
I hope this helps someone else but I'm guessing it was a stupid mistake of mine.
Sorry for all the trouble and thanks for your time!
So after a while I finally understand the issue:
When using a custom framework, all resources like images and NIB files have to be manually included in the third-party app so that it has access to those files.
My problem was that I was including the resources (stored in a bundle) into the third-party app but the framework was trying to display the View based on its own resources, which the app couldn't access, for that reason I was getting a blank screen.
I just needed to tell the framework to use the included bundle into the third-party app to display that View (using the initWithNibName: Bundle method).
See EDIT 2 in the question to see the code that solved my problem.
Hope this helps someone. :-)

"Tell Friend" example which allow selection multiple contact

I would like to add to my application a "Tell Friend" option which allow user to select multiple contacts to send them email. Contact need to be filtered to the one who have email address only.
does any one know such ready example that I could reuse.
I recently searching for the same problem and I found iTellAfriend. It works for me.
Download this source code from github/iTellafriend. Open zip file and inside src file drag iTellAFriend.h and iTellAFriend.m to your project. Check "Copy items into destination group folder(if needed)" and "Create group folder for any added folders"
In your appdelegate.m add #import "iTellAFriend.h"
Add following to your appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//[iTellAFriend sharedInstance].appStoreID = yourAppId;
[iTellAFriend sharedInstance].appStoreID = 408981381; //example
return YES;
}
Add #import "iTellAFriend.h" to your ViewController.m and anywhere in your ViewController.m call following method (preferably in a button)
if ([[iTellAFriend sharedInstance] canTellAFriend]) {
UINavigationController* tellAFriendController = [[iTellAFriend sharedInstance] tellAFriendController];
[self presentModalViewController:tellAFriendController animated:YES];
}
In iTellAFriend.m modify following
- (UINavigationController *)tellAFriendController
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:self.messageTitle];
[picker setMessageBody:[self messageBody] isHTML:YES];
return picker;
}
to
- (UINavigationController *)tellAFriendController
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
NSArray *toRecipients = [NSArray arrayWithObjects:#"xxxx#xxxx.com", #"xxxxx#xxxx.com", nil];
[picker setToRecipients:toRecipients];
[picker setSubject:self.messageTitle];
[picker setMessageBody:[self messageBody] isHTML:YES];
return picker;
}
when you click your button following scene will appear it wont send the email on simulator but on device

How to use MFMailComposeViewController

I am using MFMailComposeViewController in my app and the mail sending part seems to be OK.
But when I leave the mail app, things go wrong :
- one toolbar (UIToolbar object) has disappeared.
- one pointer (UIImageView*) has become nil, without me doing anything for that to happen.
In other words the calling environment is changed although I do not want it to change.
Where could be my mistake?
Here is my code, in case someone can see something wrong :
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError*)error
{
[controller dismissModalViewControllerAnimated:YES];
}
-(IBAction)sendAsEMail {
MFMailComposeViewController *mailComposeViewController=[[MFMailComposeViewController alloc] init];
mailComposeViewController.mailComposeDelegate=self;
[mailComposeViewController setSubject:#"Mail subject"];
[mailComposeViewController setMessageBody:#"This is for you !" isHTML:NO];
[mailComposeViewController addAttachmentData:
[NSData dataWithContentsOfFile:[[My_ViewController getDocDir] stringByAppendingPathComponent:
[pictureNames objectAtIndex:userItemSelected]]]
mimeType:#"image/png" fileName:#"Picture.png"];
if (mailComposeViewController) [self presentModalViewController:mailComposeViewController animated:YES];
[mailComposeViewController release];
}
Thanks for any piece of relevant information.
Try out this link it explain in detail
Add framework
Then .h file header files
Then .m file the mail code
Check at this link.

How to open iPhone's mail app when clicking an email link in UITextView?

I am new in iPhone devlopment. I have an UITextView in a xib. There I displaying an email address link. I want to open iPhone's mail application while clicking on that email link. How can I achieve that?
As pointed out in this answer, you can set the dataDetectorTypes property of the UITextView:
textview.editable = NO;
textview.dataDetectorTypes = UIDataDetectorTypeAll;
You should also be able to set the detectorTypes in Interface Builder.
From Apple documentation:
UIDataDetectorTypes
Defines the types of information that can be detected in text-based content.
enum {
UIDataDetectorTypePhoneNumber = 1 << 0,
UIDataDetectorTypeLink = 1 << 1,
UIDataDetectorTypeAddress = 1 << 2,
UIDataDetectorTypeCalendarEvent = 1 << 3,
UIDataDetectorTypeNone = 0,
UIDataDetectorTypeAll = NSUIntegerMax
}; typedef NSUInteger UIDataDetectorTypes;
Clicking on the email address in your UITextView should then automatically open the Mail application.
On a side note, if you want to send the email from within your app itself, you can use the MFMailComposeViewController.
Note that for the MFMailComposeViewController to be shown, Mail app needs to be installed on the device, and have an account linked to it, otherwise your app will crash.
So you can check this with [MFMailComposeViewController canSendMail]:
// Check that a mail account is available
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController * emailController = [[MFMailComposeViewController alloc] init];
emailController.mailComposeDelegate = self;
[emailController setSubject:subject];
[emailController setMessageBody:mailBody isHTML:YES];
[emailController setToRecipients:recipients];
[self presentViewController:emailController animated:YES completion:nil];
[emailController release];
}
// Show error if no mail account is active
else {
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:#"Warning" message:#"You must have a mail account in order to send an email" delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", #"OK") otherButtonTitles:nil];
[alertView show];
[alertView release];
}
MFMailComposeViewController Class Reference
In addition to the code above, once the user has pressed the send or cancel buttons you will need to dismiss the modal email view.
The MFMailComposeViewControllerDelegate protocol includes a method called "didFinishWithResult". This method will be automatically called as the view closes.
However, if you don't implement it, nothing will happen & the modal view will remain, bringing your app to a standstill!
The following code is required as a minimum:
- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
// Close the Mail Interface
[self dismissViewControllerAnimated:YES completion:NULL];
}

Resources