I have saved a pdf file in the apps documents folder on the iPad. I want the user to open that PDF file on iPad using iBooks. Is there any way to open the PDF in iBooks which is saved in documents folder of the application?
EDIT : Best option : Use UIActivityViewController
//create file path here
NSString *strFileURL = [NSTemporaryDirectory() stringByAppendingPathComponent:#"data.pdf"];
//Check if file path exists or not
BOOL checkExist = [[NSFileManager defaultManager] fileExistsAtPath:strFileURL isDirectory:nil];
if (checkExist)
{
//create NSURL object from string path
NSURL *urlFilePath = [NSURL fileURLWithPath:strFileURL];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[urlFilePath] applicationActivities:nil];
//for iOS8 check
if ( [activityViewController respondsToSelector:#selector(popoverPresentationController)] )
{
//use triggering UI element like say here its button
activityViewController.popoverPresentationController.sourceView = yourBtnSender;
}
//now present activityViewController
[self presentViewController:activityViewController animated:YES completion:NULL];
}
Another option use UIDocumentInteractionController for this:
//create file path here
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *pdfFilePath [documentsDir stringByAppendingPathComponent:yourPdfFile.pdf];// your yourPdfFile file here
NSURL *url = [NSURL fileURLWithPath:pdfPath];
//create documentInteractionController here
UIDocumentInteractionController *docController = [UIDocumentInteractionController interactionControllerWithURL:url];
//set delegate
docController.delegate = self;
//provide button's frame from where popover will be lauched
BOOL isValid = [docController presentOpenInMenuFromRect:yourReadPdfButton.frame inView:self.view animated:YES]; // Provide where u want to read pdf from yourReadPdfButton
//check if its ready show popover
if (!isValid)
{
NSString * messageString = [NSString stringWithFormat:#"No PDF reader was found on your device. In order to consult the %#, please download a PDF reader (eg. iBooks).", yourPDFFileTitle];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:messageString delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
Use UIDocumentInteractionControllerDelegate method
// UIDocumentInteractionController delegate method
- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller {
NSLog(#"dissmissed");
}
Credit goes to #Mutix 's answer
Related
I have UIWebView which has loaded an image from the internet. I have a button which opens a UIActionSheet to give you the option to tweet this picture in the UIWebView. If you hit Tweet in the UIActionSheet it disappears and you see the UIWebview again. In the background the image is loading from the internet to attach it to the tweet. This may take several time depending of the imagesize.
I want to display now an information for the user that he knows what is going. I want to display a MBProgressHUD while the user is waiting that the Twitterconsole appears.
I try to start the HUD when the button is press and the UIActionSheet disappears but it didn't came up. It comes up in background when the Twitterconsole appears. This a little to late.
So what in the best place to start/stop the HUD?
Thanks
- (void) actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0)
{
[self hudTweet];
[self tweet];
}
- (void) tweet {
if ([TWTweetComposeViewController canSendTweet])
{
TWTweetComposeViewController *tweetSheet =
[[TWTweetComposeViewController alloc] init];
[tweetSheet setInitialText:
#"Tweeting from "];
NSString *fullURL = beverageViewString;
NSURL *url = [NSURL URLWithString:fullURL];
NSString *paths = NSTemporaryDirectory();
NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:paths])
[[NSFileManager defaultManager] createDirectoryAtPath:paths withIntermediateDirectories:NO attributes:nil error:&error];
NSString *filePath = [paths stringByAppendingPathComponent:[self.title stringByAppendingFormat:#".jpeg"]];
NSData *jpegFile = [NSData dataWithContentsOfURL:url];
[jpegFile writeToFile:filePath atomically:YES];
[tweetSheet addImage:[UIImage imageWithContentsOfFile:filePath]];
[self presentModalViewController:tweetSheet animated:YES];
}
else
{
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Sorry"
message:#"You can't send a tweet right now because your account isn't configured"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
- (void) hudTweet {
HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
[self.view.window addSubview:HUD];
HUD.delegate = self;
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Loading";
HUD.detailsLabelText = #"updating data";
}
You are downloading your image in the main thread synchronously and thereby preventing the UI from updating. See this answer for a detailed explanation and possible workarounds.
The best option for you though, is to download the image asynchronously using something like NSURLRequest (see the showURL: example and according delegate callbacks).
I am trying to post a photo to Instagram through my app. I am using UIDocumentInteractionController according to INstagram guidlines
in my .h file
UIDocumentInteractionController *documentInteractionController;
in my .m file
NSString *fileToOpen = [[NSBundle mainBundle] pathForResource:#"IMG_0192" ofType:#"jpg"];
fileToOpen = [fileToOpen substringToIndex:[fileToOpen length] - 3];
fileToOpen=[NSString stringWithFormat:#"%#ig",fileToOpen];
NSURL *instagramURL = [NSURL URLWithString:#"instagram://app"];
NSLog(#"%#",fileToOpen);
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
//imageToUpload is a file path with .ig file extension
/*UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#""
message:#"Can open app!"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
*/
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:fileToOpen]];
self.documentInteractionController.UTI = #"com.instagram.photo";
self.documentInteractionController.annotation = [NSDictionary dictionaryWithObject:#"Its a testing" forKey:#"InstagramCaption"];
is am missing something.??it is not working.
I think your photo ID or file URL is not correct here. I've done this successfully with the following code snippet:
in your .h file:
#property (nonatomic, retain) UIDocumentInteractionController *docDic;
also add the following delegate:
UIDocumentInteractionControllerDelegate
in your .m file:
synthesize the docDic object
Write the following method:
-(UIDocumentInteractionController *)setupControllerWithURL:(NSURL*)fileURL usingDelegate:(id<UIDocumentInteractionControllerDelegate>)interactionDelegate{
UIDocumentInteractionController *interactionController = [UIDocumentInteractionController interactionControllerWithURL: fileURL];
interactionController.delegate = interactionDelegate;
return interactionController;
}
Then add the following code snippet to your shareToInstagram function:
NSString *fileToOpen = [[NSBundle mainBundle] pathForResource:#"IMG_0192" ofType:#"jpg"];
fileToOpen = [fileToOpen substringToIndex:[fileToOpen length] - 3];
fileToOpen=[NSString stringWithFormat:#"%#.ig",fileToOpen];
NSURL *instagramURL = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"file://%#", fileToOpen]];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]){
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:fileToOpen]];
self.documentInteractionController.UTI = #"com.instagram.photo";
[self.dic presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}
Hopefully it will help you. Best of luck. :-)
Holy Dudes from stackoverflow,
MY PROBLEM: I need to send an email with 3 attachments. The first that is the .txt, is going well, no problems with him, but the problem is with the pictures. I capture a printscreen with this:
-(IBAction)screenShot{
maintimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(update) userInfo:nil repeats:YES];
}
-(void)update{
time = time + 1;
if(time == 2){
[self hideThem]; //hides the buttons
UIGraphicsBeginImageContext(self.bounds.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(screenImage, nil, nil, nil);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"GRAPH SAVED" message:#"YOUR GRAPH HAS BEEN SAVEN IN THE PHOTO ALBUM" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
[maintimer invalidate];
time = 0;
}
[self bringThem]; //brings the buttons back
}
But now i need to get this image i created! I tried using the same code i use for the text:
-(IBAction)sendMail
{
(..)
//HERE IS WHERE THE NAME IS GIVEN
NSString *filename = [NSString stringWithFormat:#"%f.txt", [[NSDate date] timeIntervalSince1970]];
//THIS IS GOING TO STORE MY MESSAGE STUFF
NSString *content = [[NSMutableString alloc]init];
(...) //LOTS OF UNNECESSARY CODE
//HERE IS WHERE IT BILDS THE FILE
[self writeToTextFile:filename content:content];
//HERE IS THE CODE WHERE IT ATTACHES THE FILE
[self sendMailWithFile:filename];
//[content release];
}
-(void)sendMailWithFile : (NSString *)file
{
//THIS IS THE CODE THAT GETS THE TEXT
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:#"%#/%#", documentsDirectory, file];
NSData *data = [[NSData alloc] initWithContentsOfFile:fileName];
//THIS WAS MY TRY TO GET THE PHOTO ON THE SAME STYLE OF THE TEXT
NSArray *photoPath = NSSearchPathForDirectoriesInDomains(NSPicturesDirectory, NSUserDomainMask, YES);
NSString *photoDirectoryForFirstPhoto = [photoPath objectAtIndex:0];
NSString *photoName_First = [NSString stringWithFormat:#"%#/%#", photoDirectoryForFirstPhoto, /*I DO NOT HAVE THE PHOTO NAME*/#"FirstPhoto"];
NSData *photoData_First = [[NSData alloc] initWithContentsOfFile:photoName_First];
MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
if ([MFMailComposeViewController canSendMail])
{
mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;
[mailComposer setSubject:#"RK4 data"];
[mailComposer addAttachmentData:data mimeType:#"text/plain" fileName:#"[RK4][EQUATION][TEXT]"];
[mailComposer addAttachmentData:photoData_First mimeType:#"image/png" fileName:#"[RK4][EQUATION][IMAGE]"];
[mailComposer setMessageBody:#"iCalculus Runge-Kutta data." isHTML:NO];
[self presentModalViewController:mailComposer animated:YES];
}
else (...)
[mailComposer release];
[data release];
}
So that's my problem. I need to find a way to get the printscreen i took and attach it.
Because i need to come up with all the attaches in the email as soon as he clicks the "SEND MAIL" button.
Thanks.
Rather than saving to your photo library, you should save to documents directory, or tmp directory, to get documents directory you can use the following.
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* dd = [paths objectAtIndex:0];
NSString *path = [dd stringByAppendingPathComponent:#"file.png"];
[UIImagePNGRepresentation(screenImage) writeToFile:path atomically:NO];
Take a look here for how to embed the image directly inside the email using base-64, that should be much cleaner than dumping temporary images to the users saved photos album.
Edit:
Category for handling base 64 with NSData, use the download towards the bottom.
I have this code:
#define ALERT(X) {UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Info" message:X delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];[alert show];[alert release];}
- (id)readPlist:(NSString *)fileName {
NSData *plistData;
NSString *error;
NSPropertyListFormat format;
id plist;
NSString *localizedPath = [[NSBundle mainBundle] pathForResource:fileName ofType:#"plist"];
plistData = [NSData dataWithContentsOfFile:localizedPath];
plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if (!plist) {
NSLog(#"Error reading plist from file '%s', error = '%s'", [localizedPath UTF8String], [error UTF8String]);
[error release];
}
return plist;
}
- (void)writeToPlist: (NSString*)a
{
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"data.plist"];
NSMutableArray* pArray = [[NSMutableArray alloc] initWithContentsOfFile:finalPath];
[pArray addObject:a];
[pArray writeToFile:finalPath atomically: YES];
ALERT(#"finished");
/* This would change the firmware version in the plist to 1.1.1 by initing the NSDictionary with the plist, then changing the value of the string in the key "ProductVersion" to what you specified */
}
- (void)viewDidLoad {
[super viewDidLoad];
[self writeToPlist:#"this is a test"];
NSArray* the = (NSArray*)[self readPlist:#"data"];
NSString* s = [NSString stringWithFormat:#"%#",the];
ALERT(s);
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
On the simulator the second alert shows the content of the file correctly but on the device it shows nothing?? What's i'm doing wrong? Please show a code/snippet....
The problem is that you could not write a file into mainBundle folder, only Documents folder is accessable on your Device.
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
I am working on an iPhone project in which I need save camera images to disk and file but the code below fails:
(************
-(void)imagePickerController:(UIImagePickerController *) picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissModalViewControllerAnimated:YES];
imageView.image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
imgglobal =imageView.image;
NSString *newFilePath = [NSHomeDirectory() stringByAppendingPathComponent: #"~/Users/abc/Library/Application Support/iPhone Simulator/User/Applications/SAVE_IMAGE_TEST1.JPG"];
NSData *imageData = UIImageJPEGRepresentation(imageView.image, 1.0);
NSData *data = imageData;
if (imageData != nil) {
[imageData writeToFile:newFilePath atomically:YES];
}
if ([[NSFileManager defaultManager] createFileAtPath:#"~/Users/abc/Library/Application Support/iPhone Simulator/User/Applications/SAVE_IMAGE_TEST1.JPG" contents:data attributes:nil])
{
UIAlertView *successAlert = [[UIAlertView alloc] initWithTitle:#"Success" message:#"Image was successfully saved to the Photo Library." delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[successAlert show];
[successAlert release];
} else {
UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle:#"Failure" message:#"Failed to save image to the Photo Library." delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[failureAlert show];
[failureAlert release];
}
}
You shouldn't have a hard coded path to the simulator directories. That will fail on the device or when the simulator resets. Neither should you save user data anywhere but the app's Document folder.
Instead use:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *pathToDocuments=[paths objectAtIndex:0];
This will return the current path the app's Document directory regardless of where it is run or what has changed.
You should never use absolute paths in iPhone code because the system scrambles the paths for security. Always use the functions that dynamically retrieve the paths as needed.