I have to load multiple cordova apps based on user access in Native IOS app.
I want to load the zip files dynamically on app launch and store them in Documents or Libraries folder and then unzip these files, then I'm trying to load cordova views directly using below code in my view controller
CDVViewController* viewController = [CDVViewController new];
viewController.wwwFolderName=#"www";
viewController.startPage=#"abc.html";
viewController.view.frame=CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
But the problem is that the wwwFolderName is not working if I point dynamically to Documents or Library folder it only accepts root folders which are shipped with the app, so I want to know how should I achieve this use case.
If I understood you correct, here is an example, where YOUR_APP_PATH is string path to the directory, where you want to store you application sources, and YOUR_SEARCH_PATH is NSLibraryDirectory or NSDocumentsDirectory
- (void)openApp
NSString *filePath = [self directoryToApp:YOUR_APP_PATH forSearchPath:YOUR_SEARCH_PATH];
NSURL *url = [NSURL fileURLWithPath:filePath];
NSURLRequest *request = [NSURLRequest requestWithURL: url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval: 20.0];
[self.webView loadRequest:appReq request;
}
- (NSURL *)directoryToApp:(NSString *)appPath forSearchPath:(NSSearchPathDirectory)searchPath{
NSString *basePath = [self applicationDocumentsDirectory:searchPath].absoluteString;
return [NSURL fileURLWithPath:[basePath stringByAppendingString:appPath]];
}
- (NSURL *)applicationDocumentsDirectory:(NSSearchPathDirectory)searchPath
{
return [[[NSFileManager defaultManager] URLsForDirectory: searchPath
inDomains: NSUserDomainMask] lastObject];
}
let your wwwFolderName be following:
viewController.wwwFolderName=[NSString stringWithFormat: #"file://%#/www", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
this will point the start directory to your www folder inside document directory.
Related
I'm currently updating one of my apps to be iOS9 compatible, and I'm having trouble with the share to Instagram function. I'm using the Instagram hooks as stated on their developer site: (https://instagram.com/developer/mobile-sharing/iphone-hooks/)
The image I wish to share is being generated successfully, with the .igo suffix, and the functionality is still working as intended on iOS8. It just seems to have broken with the new version of iOS.
Here's the code for sharing to Instagram, using the UIDocumentInteractionController:
NSURL *instagramURL = [NSURL URLWithString:#"instagram://app"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
//convert image into .png format.
NSData *imageData = UIImagePNGRepresentation(image);
//create instance of NSFileManager
NSFileManager *fileManager = [NSFileManager defaultManager];
//create an array and store result of our search for the documents directory in it
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//create NSString object, that holds our exact path to the documents directory
NSString *documentsDirectory = [paths objectAtIndex:0];
//add our image to the path
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"insta.igo"]];
//finally save the path (image)
[fileManager createFileAtPath:fullPath contents:imageData attributes:nil];
CGRect rect = CGRectMake(0 ,0 , 0, 0);
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIGraphicsEndImageContext();
NSString *fileNameToSave = [NSString stringWithFormat:#"Documents/insta.igo"];
NSString *jpgPath = [NSHomeDirectory() stringByAppendingPathComponent:fileNameToSave];
NSLog(#"jpg path %#",jpgPath);
NSString *newJpgPath = [NSString stringWithFormat:#"file://%#",jpgPath];
NSLog(#"with File path %#",newJpgPath);
NSURL *igImageHookFile = [[NSURL alloc]initFileURLWithPath:newJpgPath];
NSLog(#"url Path %#",igImageHookFile);
self.documentController = [UIDocumentInteractionController interactionControllerWithURL:igImageHookFile];
[self.documentController setDelegate:self];
[self.documentController setUTI:#"com.instagram.exclusivegram"];
[self.documentController presentOpenInMenuFromRect:rect inView:self.view animated:YES];
} else {
NSLog (#"Instagram not found");
}
It's probably worth mentioning I've already configured the URL schemes in the info.plist as required with the iOS9 changes.
The UIDocumentInteractionController does appear, and has the option 'Copy to Instagram'. Pressing this option just leads to the controller being dismissed, with no log messages or breakpoints being called on the controller's delegate (set to self; the view controller).
If anyone has, or has had trouble with this, it would be great to hear your thoughts, or better yet, how it was solved.
Update
It's also worth mentioning, on an iOS8 device, the Document Interaction Controller shows an 'Open in Instagram' button. The iOS9 device shows a 'Copy to Instagram' button.
After changing this line of code:
NSURL *igImageHookFile = [[NSURL alloc] initFileURLWithPath:newJpgPath];
to this:
NSURL *igImageHookFile = [NSURL URLWithString:newJpgPath];
The Instagram-share function for iOS 9 is now working. It seems that the previous line of code, converting the NSString to an NSURL would place "--://file" at the end of the URL path, which doesn't seem to register well with iOS 9. Simply converting the NSString to NSURL without initialising as a file URL seems to work.
You have to add a new key to your Info.plist file; it's an iOS 9 change for URL schemes. Check out the first answer for this question: iOS 9 not opening Instagram app with URL SCHEME. And just FYI, iOS 9 changes the "Open in Instagram" title for the UIDocumentInteractionController to "Copy to Instagram." Not sure why.
I am trying to open a PDF file that I have stored locally within my app in iBooks. The app currently has a list of "literature" in a table view and when each cell is tapped the app segues to a webView that displays the PDF file (works great). I have made a BarButton at the top right in navBar to allow the user to open the PDF in iBooks (so they can store it on his/her device).
So far the button will open a UIDocumentInteractionController that displays all apps on the device that can open the file (after checking if iBooks is installed). Then when I click the iBooks icon the app crashes. I was able to revise the code so that iBooks opens without crashing, but the PDF file is not carried through so it's kind of pointless (code below is reverted back to when it crashes).
Code below is inside the IBAction of the barButton...
NSString *path = [[NSBundle mainBundle] pathForResource:litFileName ofType:#"pdf"];
NSURL *targetURL = [NSURL fileURLWithPath:path];
UIDocumentInteractionController *docController = [UIDocumentInteractionController interactionControllerWithURL:targetURL];
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"itms-bookss:"]])
{
[docController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
NSLog(#"ibooks is installed");
}
else
{
NSLog(#"no ibooks installed");
}
Fixed it! Took some time away from the project and after coming back two weeks later I figured it out in <15 minutes.
So it was a memory issue for the docController and by declaring in the .h file and using (retain) it works perfectly. I was also able to use the [NSBundle mainBundle] method as well.
.h
#property (retain)UIDocumentInteractionController *docController;
.m
#synthesize docController;
//in bar button IBAction
NSString *path = [[NSBundle mainBundle] pathForResource:litFileName ofType:#"pdf"];
NSURL *targetURL = [NSURL fileURLWithPath:path];
docController = [UIDocumentInteractionController interactionControllerWithURL:targetURL];
if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"itms-books:"]]) {
[docController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
NSLog(#"iBooks installed");
} else {
NSLog(#"iBooks not installed");
}
On iOS 8 the layout of the file system changed and sharing files directly from the main bundle no longer works. Copy the file to the documentsdirectory and share it from there.
Here is how to create the file path:
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *fileName = [NSString stringWithFormat:#"%#.pdf",litFileName];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSURL *url = [NSURL fileURLWithPath:filePath];
I use this code to save some PDF data to a file, send it to another app using the "Open In" menu, then delete the file when that's done:
- (void)openIn:(NSData *)fileData {
// save the PDF data to a temporary file
NSString *fileName = [NSString stringWithFormat:#"%#.pdf", self.name];
NSString *filePath = [NSString stringWithFormat:#"%#/Documents/%#", NSHomeDirectory(), fileName];
BOOL result = [fileData writeToFile:filePath atomically:TRUE];
if (result) {
NSURL *URL = [NSURL fileURLWithPath:filePath];
UIDocumentInteractionController *controller = [[UIDocumentInteractionController interactionControllerWithURL:URL] retain];
controller.delegate = self;
[controller presentOpenInMenuFromBarButtonItem:self.openInButton animated:TRUE];
}
}
- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller {
// when the document interaction controller finishes, delete the temporary file
NSString *fileName = [NSString stringWithFormat:#"%#.pdf", self.name];
NSString *filePath = [NSString stringWithFormat:#"%#/Documents/%#", NSHomeDirectory(), fileName];
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
}
This has worked fine until iOS 8. Now, the file is created and I can verify that it contains the correct content, the Open In menu appears, I can select an app, and the delegate method runs and cleans up the file. But instead of iOS switching to the selected app and copying the file into it as it did before, the Open In menu simply closes when I select an app, and the file is not copied.
This works if I give the UIDocumentInteractionController an existing file. It also works if I use the provided fileData but change the destination filename to the filename of an existing file. This suggests a permissions problem -- as if new files are created in iOS 8 with default permissions that UIDocumentInteractionController can't read.
Does anyone know what's happening and how I can work around it?
It looks like the order of operations has changed slightly in iOS 8. DidDismissOpenInMenu used to run after the file was finished sending, but now it runs after the file begins sending. This means my cleanup code was sometimes running before the file was finished sending, leaving no file to send. I figured this out after noticing that smaller files were being sent okay; apparently the processing for smaller files was finishing before my cleanup code got them, but the processing for larger files was not.
To ensure the correct timing, but also clean up files that are created when the user opens the DocumentInteractionController and then dismisses the controller without doing anything, I changed my methods like this:
- (void)openIn:(NSData *)fileData {
// save the PDF data to a temporary file
NSString *fileName = [NSString stringWithFormat:#"%#.pdf", self.name];
NSString *filePath = [NSString stringWithFormat:#"%#/Documents/%#", NSHomeDirectory(), fileName];
BOOL result = [fileData writeToFile:filePath atomically:TRUE];
if (result) {
self.sendingFile = FALSE;
NSURL *URL = [NSURL fileURLWithPath:filePath];
UIDocumentInteractionController *controller = [[UIDocumentInteractionController interactionControllerWithURL:URL] retain];
controller.delegate = self;
[controller presentOpenInMenuFromBarButtonItem:self.openInButton animated:TRUE];
}
}
- (void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application {
// the user chose to send the file, so we shouldn't clean it up until that's done
self.sendingFile = TRUE;
}
- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller {
if (!self.sendingFile) {
// the user didn't choose to send the file, so we can clean it up now
[self openInCleanup];
}
}
- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application {
// the user chose to send the file, and the sending is finished, so we can clean it up now
[self openInCleanup];
self.sendingFile = FALSE;
}
- (void)openInCleanup {
// delete the temporary file
NSString *fileName = [NSString stringWithFormat:#"%#.pdf", self.name];
NSString *filePath = [NSString stringWithFormat:#"%#/Documents/%#", NSHomeDirectory(), fileName];
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
}
Update for iOS 11
Before iOS 11, it seems that the operating system kept a copy of the file available until the receiving app was finished reading it, even though my cleanup function ran as soon as the file was sent out from my app. In iOS 11, this changed and the receiving app fails to read the file because my app deletes it before that's done. So now instead of saving the temporary file to Documents and using the openInCleanup method to delete it immediately, I'm saving the temporary file to tmp and emptying the tmp folder next time the app launches. This approach should also work with older iOS versions. Just remove openInCleanup, change Documents to tmp in the paths, and add this to applicationDidFinishLaunching:
// clear the tmp directory, which will contain any files saved for Open In
NSString *tmpDirectory = [NSString stringWithFormat:#"%#/tmp", NSHomeDirectory()];
NSArray *tmpFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirectory error:NULL];
for (NSString *tmpFile in tmpFiles) {
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:#"%#/%#", tmpDirectory, tmpFile] error:NULL];
}
After reading this post, I already hoped to have found the solution to a similar problem:
For me, as of iOS 8, sharing was only working with Mail.app. It was failing for Dropbox, etc.
Turns out it was something else:
On my interactionController I was setting an annotation like this:
interactionController.annotation = #"Some text"
For unknown reasons, this prevented Dropbox to open at all. There were no error messages or anything. Removing this line solved the issue.
This is what I'm trying to do:
Get a .pdf from external URL
Save it into my local disk
Display it in a WebView
Allow the user to move the .pdf to another app who can read .pdf
Everything from 1 to 3 works fine. But nothing is moved/shared to/with other apps. I can't understand what I'm doing wrong. This is what I'm doing.
How I save the pdf in the Documents folder (viewDidLoad):
// to save the pdf into local file system (tempString is the pdf url)
NSData *pdfData = [[NSData alloc]
initWithContentsOfURL:[NSURL URLWithString:tempString]];
NSString *resourceToPath = [[NSString alloc]
initWithString:[[[[NSBundle mainBundle] resourcePath]
stringByDeletingLastPathComponent]
stringByAppendingPathComponent:#"Documents"]];
NSString *filePAth = [resourceToPath stringByAppendingPathComponent:#"myPDF.pdf"];
[pdfData writeToFile:filePAth atomically:YES];
// to populate the WebView
NSURL *url2 = [NSURL fileURLWithPath:filePAth];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url2];
[my_web_view setUserInteractionEnabled:YES];
//[editoriale_view setDelegate:self];
[my_web_view loadRequest:requestObj];
In my viewDidLoad() function I create a button to allow the user to open a list of apps who can read .pdf files:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:self
action:#selector(show_Button)];
And here's my show_Button function:
-(void)show_Button {
NSString *resourceToPath = [[NSString alloc]
initWithString:[[[[NSBundle mainBundle] resourcePath]
stringByDeletingLastPathComponent]
stringByAppendingPathComponent:#"Documents"]];
NSString *filePAth = [resourceToPath
stringByAppendingPathComponent:#"myPDF.pdf"];
NSLog(#"filePath = %#", filePAth);
NSURL *url2 = [NSURL fileURLWithPath:filePAth];
NSLog(#"url2 = %#", url2);
UIDocumentInteractionController *docContr = [UIDocumentInteractionController
interactionControllerWithURL:url2];
[docContr presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}
When I try this on my device everything works fine until I tap on one of the icons in the list (i.e. the iBooks one). Then the app closes (it doesn't crash, it simply closes).
Here's what the console prints for the two logs I put in the show_Button function:
1. filePath = /Users/[MY_USER]/Library/Application Support/iPhone
Simulator/6.1/Applications/[MY_EXAD_APP_ID]/Documents/myPDF.pdf
2. url2 = file://localhost/Users/[MY_USER]/Library/Application%20Support/
iPhone%20Simulator/6.1/Applications/[MY_EXAD_APP_ID]/Documents/myPDF.pdf
Anyone wants to try to make me understand what I'm doing wrong? I'm using Xcode 4.6. I browsed my iPhone app file system with a third-party software and the file "MyPDF.pdf" actually IS in the Documents" folder, and that's clear because the WebView is correctly populated.
Change CGRectZero to self.view.bounds when you display the document controller.
Solved. I had not implemented the UIDocumentenInteractionController delegate in the .h file. Now I have and everything works fine. Thank you to #trojanfoe for the useful hint.
i am working on an iPhone app, in my project I added an HTML5 page that is a template, and have a webview and want to load it on viewdidload. I can't seem to be able to access it, I am trying this :
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains( NSAllApplicationsDirectory, NSUserDomainMask, YES ) ;
NSString *documentDirectory = [ documentDirectories objectAtIndex: 0 ] ;
NSString *longPath = [ documentDirectory stringByAppendingFormat:#"/%#" filename ] ;
I am a bit confused? How can I achieve this? do I need to tell xcode that this html5 needs to be built and sent to a specific folder at runtime? like treated as a resource?
I am new to xcode coming from a .NET environment, so maybe the terminology is a bit awkward.
Thanks
If it's part of the project it won't be in the documents directory it'll be in your application bundle. For example:
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:filename ofType:#"html"]];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:req];