I´m testing Apple Watch OS 2 and I´m trying to send a image from the application to the watch. According to Apple, I shall use WCSession transferFile to do this.
Use the transferFile:metadata: method to transfer files in the background. Use this method in cases where you want to send more than a simple dictionary of values. For example, use this method to send images or file-based documents.
for example:
NSString *string = [[NSBundle mainBundle] pathForResource:#"my_image" ofType:#"png"];
NSURL *path = [NSURL URLWithString:string];
[[WCSession defaultSession] transferFile:path metadata:#{#"meta1":#"meta2"}];
It all looks ok in the debugger, the path is correct and the file is accessible (checked with NSFileManager) and readable.
However, everytime I try I get a callback to the didFinishFileTransfer function, including an error:
Error Domain=WCErrorDomain Code=7013 "The operation couldn’t be completed. (WCErrorDomain error 7013.)"
Looking up the error:
WCErrorCodeFileAccessDenied
An error indicating that a file could not be transferred because it was inaccessible.
Available in watchOS 2.0 and later.
It seems the file is not accessible by the send function? I have tried things like resaving the file to another directory etc, but nothing seems to work.
Anyone got an idea?
The URL you are creating is not a fileURL. Try:
NSURL *path = [NSURL fileURLWithPath:string];
I managed to solve the issue!
It was because my path did not start with file://
The following code worked just fine:
NSString *string = [[NSBundle mainBundle] pathForResource:#"my_image" ofType:#"png"];
string = [NSString stringWithFormat:#"file://%#", string];
NSURL *path = [NSURL URLWithString:string];
[[WCSession defaultSession] transferFile:path metadata:#{#"meta1":#"meta2"}];
So it´s quite picky regarding the path.
Related
I am working on widget app. I am totally new to Today Extension. I want to share data between app and today extension. I have created one database. I have 4 tables in that database. I found this code to create database for App Groups :
NSString *appGroupId = #"group.appname";
NSURL *appGroupDirectoryPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId];
dataBaseURL = [appGroupDirectoryPath URLByAppendingPathComponent:#"database.sqlite"];
NSLog(#"dataBaseURL %#", dataBaseURL);
It worked. My SQLite file has been created. But It does't show my tables. It shows empty database. I don't have any idea about it. Please help.
If you are creating new database then it will obviously empty.
first thing you can create data base with tables in objective c. there is no need to create database from outside the xcode and drag and drop yto xcode. you can refer this techotopia tutorial for that.
Now if you put database in your main bundle by drag and drop then you can access that like,
NSString *databasePath = [[NSBundle mainBundle] pathForResource:#"myDbName" ofType:#"sqlite"];
by this way you can get your database path. here pathforresource is your database name, i think database in your case and oftype is extention, i think sqlite in your case.
now you get path as string if you want it in url then you can convert it in url like,
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:filePath];
or
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
Hope this will help :)
This is strange, but basically I download and save a video locally, and the store the url path to provide to an AVPlayer to play.
This works fine the first time I do it. I download a file, and then I can play it to my hearts content as many times UNTIL I exit the app. When I launch the app a second time, I now get a black screen when I try to play the same exact video using the same exact path.
Because I am using the Simulator I can verify that the videos and pictures indeed very much still exist in the same folder I saved them to, and I can still play them if I click on them from the Finder.
Maybe it's a caching issue? If it matters, I've saved them straight to the Library directory as I test this.
Relevant Code:
NSString *outputFile = [NSString stringWithFormat:#"video_%#.mp4", guid];
NSString *outputDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *tempPath = [outputDirectory stringByAppendingPathComponent:outputFile];
NSURL *fileURL = [NSURL fileURLWithPath:tempPath];
// save the video to the URL
Then I "persist" it using an NSString [fileURL path] (The way I've built this out, assume the solution requires an NSString to NSURL conversion).
Later I create an AVPlayerItem:
NSURL *url = [NSURL fileURLWithPath:persistedObject.contentURL];
NSLog(#"url: %#", url); // prints a valid location**
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:url];
** for example this is a sample url location
url: file:///Users/gabriel/Library/Developer/CoreSimulator/Devices/CE1FC933-808C-4003-9BE4-DEC59B787FF7/data/Containers/Data/Application/FAD072B4-B5B0-4487-8A76-57B047324A00/Library/picture_D8DEAFA5-0843-4AA3-BB32-C61E32D13579.mp4
It's been suggested I use URLForDirectory:inDomain:appropriateForURL:create:error: and URLByAppendingPathComponent: instead, which I will look into. But still confused as to why it would play when I first download it, but not after app exits when it's the same exact file.
You've made a classic mistake. You are persisting the full path. But the full path changes. Never persist a full path. Only persist the part of the path relative to the value obtained from NSSearchPathForDirectoriesInDomains.
Given what you are doing, you should only persist the base filename (outputFile). Then when the app starts, you rebuild the full path again like you did originally but use the persisted filename to append it to the dynamically obtained path to the application support folder.
Here is the NSURL object that I am using for creating and accessing important configuration file on iOS with features:
hidden from user
not user generated file (storing configuration related to user)
not temp or cache (not possible to create later with existing data)
must be backed up by iCloud/iTunes
[NSURL fileURLWithPath:[[NSSearchPathForDirectoriesInDomains(
NSLibraryDirectory,
NSUserDomainMask,
YES) objectAtIndex:0]
stringByAppendingString:#"/important.txt"]];
As suggested in FileSystemOverview (developer.apple.com), I am storing this file under Library.
Maybe better way is storing it under Library/Application Support.
Using NSSearchPathForDirectoriesInDomains, which takes:
enum NSSearchPathDirectory
NSApplicationDirectory
NSDeveloperApplicationDirectory
NSLibraryDirectory
NSDeveloperDirectory
NSApplicationSupportDirectory
...
enum NSSearchPathDomainMask
NSUserDomainMask
NSLocalDomainMask
NSSystemDomainMask
...
BOOL expandTilde
Is this the correct way of storing such a file?
There are couple of alternatives for NSSearchPathDirectory and NSSearchPathDomainMask.
Also what about the expandTilde, on iOS is it necessary?
Is there a better way of doing it, instead of creating path as a NSString using objectAtIndex and appending file name then converting it to NSURL?
Thanks.
Using NSApplicationSupportDirectory would be my first choice for this.
But keep a few things in mind:
Unlike the "Documents" folder, the "Library/Application Support" folder doesn't exist in an iOS app sandbox by default so you must create the folder before trying to use it.
"Hidden from the user" only means that the user won't see it under normal circumstances. But the file is easily accessible by anyone with any technical knowledge.
You do want to pass YES for the expandTilde parameter so your app returns a proper path when you run the app in the simulator. On a real iOS device, it makes little difference.
Do not use stringByAppendingString: to create paths. Use stringByAppendingPathComponent:.
NSString *appSupportPath = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [appSupportPath stringByAppendingPathComponent:#"important.txt"];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
You can get a direct NSURL using NSFileManager:
NSURL *appSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] firstObject];
NSURL *fileURL = [appSupportURL URLByAppendingPathComponent:#"important.txt"];
I have a webview which i want to load using the loadHtmlString method. The problem is that I want to be able to change the img src's with images that i have previously downloaded. I also use google analitics in the html so I need to set the baseUrl to the actual url so it will work. Here comes the problem. If I put the baseUrl in, the images will not load. If I don't set the baseUrl, it works. How can I get around this, so I will be able to both use google analitycs and have the images store locally in my application? I would prefer not having to implement the google analitics sdk in my project.
A strange thing is that if I run it in simulator, and not put the "http://" prefix in front of my baseUrl, it works fine. However, when I run it on a device, I receive the following error and it doesn't work:
Domain=WebKitErrorDomain Code=101 "The URL can’t be shown"
Thanks
EDIT
If I do this, it works:
[appsWebView loadHTMLString:htmlString baseURL:nil];
However, I must provide a baseURL in order to have Google Analitics working, I have two further cases:
This one gives the above mentioned error: (it works ok in simulator but gives error when running on device)
[appsWebView loadHTMLString:htmlString baseURL:[NSURL urlWithString:#"test.com"]];
This one simply doesn't show anything: (neither loads the html string or the url)
[appsWebView loadHTMLString:htmlString baseURL:[NSURL urlWithString:#"http://test.com"]];
I incorrectly assumed that the problem was that the local image was not fully specifying the full path, but that does not appear to be the problem here. But, you are quite right that it appears (somewhat surprisingly) that you cannot specify some web-based baseURL and also reference a local image in your HTML string. No simple solutions are leaping out at me, but at the very least, it appears that you might have a couple of (not very good) options:
First, you could base64 encode the local image using some base64 library like Mike Gallagher's NSData+Base64 category, e.g.:
NSData *imageData = [NSData dataWithContentsOfFile:imagePath];
NSString *imageDataBase64 = [imageData base64EncodedString];
NSString *imageHtml = [NSString stringWithFormat:#"<img src='data:image/png;base64,%#'>", imageDataBase64];
This slows the initial rendering, but maybe it's better than nothing.
Second, you could always try leaving the baseURL as nil, removing the JavaScript that does the Google Analytics from the HTML string, and then try injecting that JavaScript via stringByEvaluatingJavaScriptFromString. This approach may or may not work depending upon the complexity of the Google Analytics JavaScript (e.g. what further web-based references it might have), but there's a outside chance you might be able to do something that way.
My apologies for assuming the problem was a trivial img URL. Clearly you had identified a more fundamental issue.
Original answer:
Create your image URLs in your HTML string to be fully qualified file URLs within your local file system:
The image is either in Documents:
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *imagePath = [documentsPath stringByAppendingPathComponent:imageName];
Or in the bundle:
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName
ofType:nil];
But, once you have fully qualified path, you should be able to use that:
NSURL *imageUrl = [NSURL fileURLWithPath:imagePath];
NSString *imageHtml = [NSString stringWithFormat:#"<img src='%#'>", imageUrl];
I would bet it's a casing issue. Take into account that the Device is case sensitive whereas the Simulator is not. Check the URL and make sure it contains the right characters.
This is my first real project. I have an app that captures several seconds of video using AVFoundation, outputs this to a file in the documents directory and lets the user preview the video before they upload it using HTTP and a PHP script on my website.
All the video capture and preview work perfectly but I am stuck on uploading the video file.
I learnt a lot from this simpleSDK video which shows how to achieve the desired effect using a video file stored in the apps main bundle.
The code from the tutorial that set up videoData ready to upload originally looked like this:
NSData *videoData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Movie" ofType:#"mov"]];
NSString *urlString = #"http://www.iphonedevnation.com/video-tutorial/upload.php";
The filename of the video file that I need to upload is always unique and generated using CFUUIDCreateString. I join this string to the path for the documents directory, add ".mov" to the end of it and save it into a text file for retrieving later.
This all works as I am able to retrieve the filename from the file and use it to preview the movie clip elsewhere in the app.
My path is in an NSString, that I have tried converting to NSURL and removing the file suffix to get it to work with the NSData *videoData.........line but it doesn't compile, I get an "No known class method for selector 'dataWithContentsOfFile:ofType.' error. I am targeting iOS 5 and using Xcode 4.3 with ARC and Storyboards.
I've been at this for best part of 5 hours now so hopefully someone can help. My code, which included tips from elsewhere on converting from a NSString to NSURL follows:
NSString *content = [[NSString alloc] initWithContentsOfFile:lastSavedTalentFilenamePath
usedEncoding:nil
error:nil];
NSLog(#"content=%#",content);
//Need to now remove the '.mov' file type identifier
NSString *shortContent= [content substringToIndex:[content length]-4];
NSLog(#"***************shortContent***************%#", shortContent);
NSURL *convertedContent = [NSURL fileURLWithPath:shortContent];
NSLog(#"***************convertedContent***********%#",convertedContent);
NSData *videoData = [NSData dataWithContentsOfFile:convertedContent ofType:#"mov"];];
There is no NSData method called dataWithContentsOfFile:ofType:
The methods available are:
+ dataWithContentsOfFile:
+ dataWithContentsOfFile:options:error:
both of which take the file location as an NSString so there's not need to convert to an NSURL