How to get Text from a Evernote note in iOS - ios

I am trying to download only image and text(probably HTML string) of a Evernote's note in my iOS app. I have successfully downloaded image from a note . But I did not find any method or process which help me to get text which are written on the note . I have used
ENSDK.framework
-(void)findAllNotes {
NSLog(#"finding all notes..");
[self.session findNotesWithSearch:nil
inNotebook:nil
orScope:ENSessionSearchScopeAll
sortOrder:ENSessionSortOrderNormal
maxResults:255
completion:^(NSArray* findNotesResults,
NSError* findNotesError) {
if (findNotesError) {
[self.session unauthenticate];
NSAssert(NO, #"Could not find notes with error %#", findNotesError);
} else {
[self processFindNotesResults:findNotesResults];
}
}];
}
- (void)processFindNotesResults:(NSArray*)results {
NSParameterAssert(results);
NSLog(#"processing find notes results..");
for (ENSessionFindNotesResult* result in results) {
[self.session downloadNote:result.noteRef
progress:NULL
completion:^(ENNote* note,
NSError* downloadNoteError) {
NSAssert(!downloadNoteError, #"Could not download note with error %#",
downloadNoteError);
[self getDataFromNote:note];
}];
}
}
-(void)getDataFromNote:(ENNote*)note {
for (ENResource* resource in note.resources) {
if ([resource.mimeType hasPrefix:#"image"]) {
UIImage* image = [[UIImage alloc] initWithData:resource.data];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *docs = [paths objectAtIndex:0];
NSString* path = [docs stringByAppendingFormat:#"/image1.jpg"];
NSData* imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, .8)];
NSError *writeError = nil;
if(![imageData writeToFile:path options:NSDataWritingAtomic error:&writeError]) {
NSLog(#"%#: Error saving image: %#", [self class], [writeError localizedDescription]);
}
}
}
}

The content of the note is available to you in the content property of your variable note; i.e. it's in the content property of an ENNote object.
Also note that in addition to accessing the content directly, the Evernote iOS SDK also includes a special method that makes it easy to display a note's content in a UIWebView:
We've made this easy-- rather than serializing it to HTML and fussing with attached image resources, we've provided a method to generate a single Safari "web archive" from the note; this is a bundled data type which UIWebView natively knows how to load directly.

Related

File written while app is in the background is not saved

I'm developing an app that can receive messages/files while it's on the background via webRTC.
When a file is received, I write it to disk. But when trying to access it later (even between app launches) that file doesn't exist.
User's document folder has NSFileProtectionCompleteUntilFirstUserAuthentication attribute.
I've tried to create the file on disk using NSData's [writeToURL:options:error:], [writeToFile:options:error:]; NSFileManager's [createFileAtPath:contents:attributes:] and also NSFileHandle's methods.
All of them successfully create the file at the designated path/url. Right after creation I check whether file exists with NSFileManager's [attributesOfItemAtPath:error:] which shows me the following:
attributes: {
NSFileCreationDate = "2018-05-07 18:47:50 +0000";
NSFileExtensionHidden = 0;
NSFileGroupOwnerAccountID = 501;
NSFileGroupOwnerAccountName = mobile;
NSFileModificationDate = "2018-05-07 18:47:50 +0000";
NSFileOwnerAccountID = 501;
NSFileOwnerAccountName = mobile;
NSFilePosixPermissions = 420;
NSFileProtectionKey = NSFileProtectionCompleteUntilFirstUserAuthentication;
NSFileReferenceCount = 1;
NSFileSize = 92156;
NSFileSystemFileNumber = 695101;
NSFileSystemNumber = 16777219;
NSFileType = NSFileTypeRegular;
}
[[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]] also shows me that the file exists after write.
Considering it could be a threading problem, I've also tried to write that file putting it on a main thread block, but result is the same. First file seems to be written but, when trying to access it afterwards it's like it never was.
Is there anything I could be missing?
edit: Added function I use to write.
- (void) saveFileData:(NSData *)fileData completionHandler:(void(^)(BOOL success))completionHandler {
NSURL *fileURL = [self fileURL];
NSError *error = nil;
[fileData writeToURL:fileURL options:NSDataWritingAtomic error:&error];
if (error) {
ZLogError(ZLogTypeFile, #"[%#] could not be saved: %#", self.fileKey, error);
completionHandler(NO);
return;
}
ZLogDebug(ZLogTypeFile, #"<file: %#> exists after write:%d", fileURL, [[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]);
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:&error];
ZLogDebug(ZLogTypeFile, #"attributes: %#", attributes);
completionHandler(YES);
}
output comes as (where Documents is the users NSDocumentDirectory in the app)
[file: /Documents/57/Downloads/Images/9d1687ab5f4374a2c00429a24316b5ccd3fb0a67.png] exists after write:1
and getting the file (an image):
- (UIImage *) imageFromURL:(NSURL *)imageURL {
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[imageURL path]];
if (!fileExists) {
ZLogDebug(ZLogTypeFile, #"[file: %#] exists: %d", imageURL, fileExists);
return nil;
}
return [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
}
in log (note I've taken out the long path before Documents directory just here):
[file: /Documents/57/Downloads/Images/9d1687ab5f4374a2c00429a24316b5ccd3fb0a67.png] exists: 1

Not able to fetch images in extension app from App group shared container in iOS 10

In my host App I am downloading custom emojis images folder after unzipping successfully saving by below url.
NSURL* shareContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.company.app.PushServiceExtn"];
And without any issue whenever user tapping on emojis icon all the custom emojis shows in grid in place of keyboard by shareContainerURL.
I have created PushNotification Service Extension where I need to show the custom emojis image by fetching emoji name from payload whenever push comes. using below code.
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
NSDictionary* mediaAttachment = [self.bestAttemptContent.userInfo objectForKey:#"media-attachment"];
NSString* attachType = [mediaAttachment objectForKey:#"attachType"];
if ([attachType isEqualToString:#"emoji"]) {
NSString* strEmojiURL = [mediaAttachment objectForKey:#"url"];
self.bestAttemptContent.title = strEmojiURL;
NSString* emojiName = [[strEmojiURL stringByRemovingPercentEncoding] lastPathComponent];
NSString* strUnpresseedEmojiPath = [self getFullPath:#"emoji/Pressed"];
NSString* strImagePath = [NSString stringWithFormat:#"%#/%# Pressed.png",strUnpresseedEmojiPath, emojiName];
NSURL* fileURL = [NSURL fileURLWithPath:strImagePath];
NSData *imageData = [NSData dataWithContentsOfURL:fileURL];
UIImage *image = [UIImage imageWithData:imageData];
if (image) {
NSError* error;
// CGRect rect = CGRectMake(0,0,50,50);
// #{UNNotificationAttachmentOptionsThumbnailClippingRectKey:(__bridge NSDictionary*)CGRectCreateDictionaryRepresentation(rect)} option dict;
UNNotificationAttachment * attachement = [UNNotificationAttachment attachmentWithIdentifier:strImagePath.lastPathComponent URL:fileURL options:nil error:&error];
if (error == nil) {
self.bestAttemptContent.attachments = #[attachement];
}
}
}
self.contentHandler(self.bestAttemptContent);
}
- (NSString *)getFullPath:(NSString *)file {
NSURL* shareContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.company.app.PushServiceExtn"];
return [shareContainerURL.path stringByAppendingPathComponent: file];
}
I am always getting valid url but second time I get image nil but first time of every image it works. Couldn't get the root cause. Any help would appreciated.
Below is the error that occurred second time for every image.
2016-10-27 17:34:59.081026 pushNotificationServiceExtension[651:34632] Attachement Error = Error Domain=UNErrorDomain Code=100 "Invalid attachment file URL" UserInfo={NSLocalizedDescription=Invalid attachment file URL}
Also please let me know how to view App Group shared container, Couldn't find way to view the files contained inside.
*Update = * File is getting deleted after showing in push notification.
From apple "UNNotificationAttachment Once validated, attached files are moved into the attachment data store so that they can be accessed by the appropriate processes. Attachments located inside an app’s bundle are copied instead of moved."
So I copy my emoji image to duplicate URL and assign it to UNNotificationAttachment.
if (imageFileURL) {
NSURL* duplicateImageURL = [self getFullPath:#"EmojiAttachment"];
if (![fileManager fileExistsAtPath:duplicateImageURL.path]) {
[fileManager createDirectoryAtPath:duplicateImageURL.path withIntermediateDirectories:NO attributes:nil error:&error];
}
emojiName = [NSString stringWithFormat:#"%# Unpressed.png", emojiName];
duplicateImageURL = [duplicateImageURL URLByAppendingPathComponent:emojiName];
[[NSFileManager defaultManager]copyItemAtURL:imageFileURL toURL:duplicateImageURL error:&error];
UNNotificationAttachment * attachement = [UNNotificationAttachment attachmentWithIdentifier:emojiName URL:[duplicateImageURL filePathURL] options:nil error:&error];
if (error == nil) {
self.bestAttemptContent.attachments = #[attachement];
}
else{
NSLog(#"Attachement Error = %#",error);
}
}

NSData WriteToFile Fails while saving a photo from gallery through Share Extension

I am Writing an app which has share extension to save selected photo to my app' local storage from iphone photo gallery.
NSData WriteToFile returns YES but I couldn't find the stored file into the directory in of which I gave path while writing.
So, in short NSData WriteToFile fails to save a photo at given path.
Below is my code.
- (IBAction)acceptButtonTapped:(id)sender
{
__block UIImage *photo;
for (NSExtensionItem *item in self.extensionContext.inputItems)
{
for (NSItemProvider *itemProvider in item.attachments)
{
if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage])
{
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *image, NSError *error) {
if(image)
{
dispatch_async(dispatch_get_main_queue(), ^{
photo = image;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy_MM_dd_hh_mm_ss"];
NSString *fileName;
fileName = [NSString stringWithFormat:#"%#.jpeg",[formatter stringFromDate:[NSDate date]]];
dataPath = [dataPath stringByAppendingPathComponent:fileName];
NSData * imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0)];
BOOL isdone = [imageData writeToFile:dataPath atomically:NO];
NSLog(#"%u", isdone);
});
}
}];
break;
}
}
}
[self.extensionContext completeRequestReturningItems:#[] completionHandler:nil];
}
Any Help would be much appreciable.
Thank you.
If you're trying to access the Document directory from the share extension, NO you can't do that. Share extension or other widgets are separate application from their containing app and therefore have their own sandbox. So you will need to use App Groups to share files.
Application groups are primarily targeted for extensions, more specifically, for widgets.
NSFileManager has a method on it containerURLForSecurityApplicationGroupIdentifier: where you can pass in the identifier you created when turning on App Groups for your apps
NSURL *containerURL = [[NSFileManager defaultManager]
containerURLForSecurityApplicationGroupIdentifier:#"group.com.company.app"];
You can save the files to this location, because you can access the shared application groups from both extension and host app.
You're modifying dataPath on each pass through the loop, appending another filename to it. That will create an ever-growing series of badly formed paths that contain all the filenames.
Don't do that. Create a new local variable filePath, and construct a filename into filePath using
filePath = [docsPath stringByAppendingPathComponent: filename];
Log your path and LOOK AT IT. When your program doesn't behave as expected, don't trust any of your assumptions, because one or more of them may be wrong.

Error in file provider app extension

I'm developing an app extension for open mode for my document management application. I have already implemented the import mode which is working fine. But in the open mode , when a third party application tries to open any documents from my storage provider, the following methods of file provider is executing multiple times,kind of an inifinite execution and in turn resulting in a memory warning exception.
- (instancetype)init
- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *))completionHandler
And also for your reference the complete code fo file provider as follows
- (NSFileCoordinator *)fileCoordinator {
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
[fileCoordinator setPurposeIdentifier:[self providerIdentifier]];
return fileCoordinator;
}
- (instancetype)init {
self = [super init];
if (self) {
[self.fileCoordinator coordinateWritingItemAtURL:[self documentStorageURL] options:0 error:nil byAccessor:^(NSURL *newURL) {
// ensure the documentStorageURL actually exists
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtURL:newURL withIntermediateDirectories:YES attributes:nil error:&error];
}];
}
return self;
}
- (void)providePlaceholderAtURL:(NSURL *)url completionHandler:(void (^)(NSError *error))completionHandler {
// Should call + writePlaceholderAtURL:withMetadata:error: with the placeholder URL, then call the completion handler with the error if applicable.
NSString* fileName = [url lastPathComponent];
NSURL *placeholderURL = [NSFileProviderExtension placeholderURLForURL:[self.documentStorageURL URLByAppendingPathComponent:fileName]];
NSUInteger fileSize = 0;
// TODO: get file size for file at <url> from model
[self.fileCoordinator coordinateWritingItemAtURL:placeholderURL options:0 error:NULL byAccessor:^(NSURL *newURL) {
NSDictionary* metadata = #{ NSURLFileSizeKey : #(fileSize)};
[NSFileProviderExtension writePlaceholderAtURL:placeholderURL withMetadata:metadata error:NULL];
}];
if (completionHandler) {
completionHandler(nil);
}
}
- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *))completionHandler {
// Should ensure that the actual file is in the position returned by URLForItemWithIdentifier:, then call the completion handler
NSError* error = nil;
__block NSError* fileError = nil;
//getting the actual fiile from the shared container
NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.company.test.NBox"];
storeURL = [storeURL URLByAppendingPathComponent:[url.path lastPathComponent]];
NSData* fileData = [NSData dataWithContentsOfFile:[storeURL path]];
// TODO: get the contents of file at <url> from model
//Writing the file data to the documentStorage location
//[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
[fileData writeToURL:url options:0 error:&fileError];
//}];
if (error!=nil) {
completionHandler(error);
} else {
completionHandler(fileError);
}
}
- (void)itemChangedAtURL:(NSURL *)url {
// Called at some point after the file has changed; the provider may then trigger an upload
// TODO: mark file at <url> as needing an update in the model; kick off update process
NSLog(#"Item changed at URL %#", url);
}
- (void)stopProvidingItemAtURL:(NSURL *)url {
// Called after the last claim to the file has been released. At this point, it is safe for the file provider to remove the content file.
// Care should be taken that the corresponding placeholder file stays behind after the content file has been deleted.
[self.fileCoordinator coordinateWritingItemAtURL:url options:NSFileCoordinatorWritingForDeleting error:NULL byAccessor:^(NSURL *newURL) {
[[NSFileManager defaultManager] removeItemAtURL:newURL error:NULL];
}];
[self providePlaceholderAtURL:url completionHandler:NULL];
}
Thanks,
Vsh
I'm also trying to develop an app extension for open mode. I haven't been successful yet but I don't get the infinite execution. Looking at your code, it's possible that storeURL in startProvidingItemAtURL: points to something inside your container. If so, then the assignment to fileData would trigger an infinite recursion.
As a test, try setting fileData with a test message like this:
NSString *message = [NSString stringWithFormat:#"This is a test."];
NSData *fileData = [NSKeyedArchiver archivedDataWithRootObject:message];
If that works, then it's a problem with storeURL and you'll have to figure out some different location to get the data.
(Incidentally, I noticed that you commented out the file coordinator in startProvidingItemAtURL:. I also ended up doing that to prevent deadlocks and because there's a note in the documentation that says "Do not use file coordination inside this method." But it's very confusing because the template code for file providers puts the file coordinator in that method!)

Image won't show up in image view after selection

I am trying to save an image in core data but after I select it in the simulator, it doesn't show up in the image view? Here is a sample of the code:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (fugitive_.image != nil) {
self.fugitiveImage.image = [UIImage imageWithData:fugitive_.image];
}
}
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
fugitive.image = UIImagePNGRepresentation([info objectForKey:UIImagePickerControllerEditedImage]);
[self dismissModalViewControllerAnimated:YES];
[picker release];
}
First, do not store images (or any binary data) in Core Data; especially on iOS. You will get far better performance storing it on disk and then storing a reference to the file location in Core Data.
Second, your sample code does not show how you are putting the data into Core Data. Therefore it is hard to suggest a solution.
Update
I did not find a simple reference to how to do this so here is one:
Image Cache Pre iOS 5.0
To set up an image cache on disk in a pre-iOS 5.0 environment you want to first create an attribute on your entity that is a NSString. In this example we will name that attribute imageFilename. Once that is complete we will want to create a subclass of NSManagedObject for our entity so that we can implement the helper methods:
#interface MyEntity : NSManagedObject
#property (nonatomic, retain) NSString *imageFilename;
#property (nonatomic, retain) NSImage *image;
#end
We are going to let Core Data manage the imageFilename since it is defined in the model. However we are going to implement the accessors for image.
#implementation MyEntity
#dynamic imageFilename;
#synthesize image = _image;
- (void)setImage:(UIImage*)image
{
NSString *filename = [self imageFilename];
if (!filename) {
filename = [[NSProcessInfo processInfo] globallyUniqueString];
[self setImageFilename:filename];
}
[_image release];
_image = [image retain];
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cachePath stringByAppendingPathComponent:filename];
NSData *data = UIImagePNGRepresentation(image);
NSError *error = nil;
if (![data writeToFile:filePath options:NSDataWritingAtomic error:&error]) {
NSLog(#"Failed to write image to disk: %#\n%#", [error localizedDescription], [error userInfo]);
return;
}
}
The -setImage: will save the image to disk into the cache directory (note that the cache directory is not backed up and can be delete by the system in the event of a low space situation). It selects a random filename if one has not been created already.
The path is intentionally not stored because the directory of the application's sandbox can change. Therefore we only want to store the filename in Core Data and resolve the path.
We also keep an in memory reference to the image so that we are not hitting disk if the image is asked for again during this entity's lifecycle. This is the reason for the #synthesize even though we are implementing the accessors.
Note that we store the images on disk as PNG. This can be expensive (the compression routines are relatively slow) but it keeps the image in a universal format which can be useful.
- (UIImage*)image
{
if (_image) return _image;
NSString *filename = [self imageFilename];
if (!filename) return nil;
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cachePath stringByAppendingPathComponent:filename];
if (![[NSFileManager defaultFileManager] fileExistsAtPath:filePath]) return nil;
_image = [[UIImage alloc] initWithContentsOfFile:filePath];
return _image;
}
The implementation of the -image is pretty much the reverse. We check to see if we have a filename; resolve the full path and load the image into memory and then return it to the caller.
- (void)prepareForDeletion
{
[super prepareForDeletion];
NSString *filename = [self imageFilename];
if (!filename) return nil;
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cachePath stringByAppendingPathComponent:filename];
NSError *error = nil;
if (![[NSFileManager defaultFileManager] removeItemAtPath:filePath error:&error]) {
NSLog(#"Potential error removing on disk image: %#\n%#", [error localizedDescription], [error userInfo]);
}
}
We want to keep our cache directory as clean as possible so that we do not create a low space situation. Therefore when the entity is going to be deleted from Core Data we want to remove the file from disk. The actual error that happens during a delete is a non-fatal issue for us. It could be an error because the file was already deleted or something else. There is no reason to completely fail for this error but it is important to log it.
- (void)willTurnIntoFault
{
[super willTurnIntoFault];
[_image release], _image = nil;
}
#end
Finally, we implement the -willTurnIntoFault method so that we can release our in-memory reference to the image at the end of this entity's lifecycle.
Image Cache iOS 5.0+
Create a binary attribute on the entity.
Turn on the "Store in External Record File" bit.
There is no step three

Resources