evernote / evernote-cloud-sdk-ios Goto Github PK
View Code? Open in Web Editor NEWEvernote Cloud SDK for iOS
Home Page: https://dev.evernote.com/
License: Other
Evernote Cloud SDK for iOS
Home Page: https://dev.evernote.com/
License: Other
Error from getSharedNotebookByAuth against a personal linked notebook: Error Domain=ENErrorDomain Code=4 "The operation couldn’t be completed. (ENErrorDomain error 4.)" UserInfo=0x7fdfb4d75540 {parameter=SharedNotebook.id}
if user have not authenticated with Evernote, we should authenticate first and then proceed with the original request
I think this may be similar to what was fixed for ListNotebooks in #45.
In ENSession.m > findNotes_nextFindInLinkedScopeWithContext, if the linked notebook is for some reason no longer available to the user, then I believe the call to findNotesMetadataWithFilter will fail with an EDAMNotFoundException.
I'm not really sure if it's a problem of library or API at all.
Step to reproduce:
listNotebooksWithCompletion:
returns this error Error Domain=ENErrorDomain Code=4 "The operation couldn’t be completed. (ENErrorDomain error 4.)" UserInfo=0x116a44170 {parameter=SharedNotebook.id}
Calling listNotebooksWithCompletion: method second time returns cached data without any error (see #18 )
In serveral places, the SDK loads resources with calls to:
[NSBundle mainBundle]
This breaks and crashes if the ENSDK is included in an iOS Framework instead of the main project.
Recommend replacing these calls with calls to [NSBundle bundleWithClass:] or other more portable call.
Hi,
I have been in touch with Matt Caroll and he suggested we report this bug here. The issue details are below.
We integrated Evernote for Business functionality by integrating the Evernote SDK 2.0. The adhoc build can be installed from testflight below.
https://testflightapp.com/install/8cc38f2189895fdb9a818c06d4ae8c87-MTI1NzY2MjQ/
Our basic functionality is that we want to list the attachments saved in Evernote for personal and business notebooks. While testing it, we found some issues that we need your help in troubleshooting.
I have attached the screenshots for your reference.
The code we are using to get list of notes with file attachments in a Notebook.
[[ENSession sharedSession] findNotesWithSearch:[ENNoteSearch noteSearchWithSearchString:@"any: resource:application/* resource:image/*"]
inNotebook:notebook
orScope:nil
sortOrder:ENSessionSortOrderRelevance
maxResults:0
completion:^(NSArray *findNotesResults, NSError *findNotesError) {
if (findNotesError) {
if (block) {
block(nil, findNotesError);
}
} else if (findNotesResults.count) {
[SEEvernoteHelper getNoteMetaDataFromResultList:findNotesResults onCompletion:block];
} else {
if (block) {
block(nil, nil);
}
}
}];
For my app, it's all about notebooks full of notes with image resources. For maximum performance, I run findNotes to return batches of notes with their resource GUIDs and resourceAttributes...all in one network call. If I used findNotesMetadata, I would not get the resource GUIDs nor the resourceAttributes unless I made additional network calls to the service, which would be much slower.
What I would like to see going forward is some sort of preservation of the more performant means of accessing the API. Whether that means un-deprecating the findNotes API, or whether that means somehow enhancing the NoteMetadataResults to include a list of resource attributes instead of just the largest one, or whatever.
Is there a writeup somewhere of the process the SDK/API go through to decide which version of Evernote to authenticate to?
Both with the old iOS SDK and this one, I get a number of reports of issues with the authentication process internationally. It would help me troubleshoot these reports if I knew exactly what the intended logic is behind the authentication process.
I think it many cases where users have seen this issue, they have the Evernote app authenticated and working, but their iOS region settings may conflict with the version of Evernote they are logging into, or similar. Typically, the reports say that attempting to link Evernote from my app will open the Evernote app, provide the auth dialog, then return them to my app – but the session does not establish a link.
I haven't been able to reproduce the problems, so it's been hard to troubleshoot.
Thanks for any ideas on how best to troubleshoot these issues.
Everything but simple note browse/viewer function does not work
the App Notebook key work fine, but my own key does not work in this case
error log:
2014-05-22 21:11:13.099 EvernoteSDKSample[91162:60b] ENSDK ERROR: findNotes: Failed to find notes (personal). Error Domain=ENErrorDomain Code=5 "The operation couldn’t be completed. (ENErrorDomain error 5.)" UserInfo=0x1096390c0 {EDAMErrorCode=3, parameter=authenticationToken}
2014-05-22 21:11:13.118 EvernoteSDKSample[91162:60b] findNotesError: Error Domain=ENErrorDomain Code=5 "The operation couldn’t be completed. (ENErrorDomain error 5.)" UserInfo=0x1096390c0 {EDAMErrorCode=3, parameter=authenticationToken}
2014-05-22 21:11:38.721 EvernoteSDKSample[91162:60b] ENSDK ERROR: findNotes: Failed to find notes (personal). Error Domain=ENErrorDomain Code=5 "The operation couldn’t be completed. (ENErrorDomain error 5.)" UserInfo=0x10987e220 {EDAMErrorCode=3, parameter=authenticationToken}
2014-05-22 21:11:38.741 EvernoteSDKSample[91162:60b] findNotesError: Error Domain=ENErrorDomain Code=5 "The operation couldn’t be completed. (ENErrorDomain error 5.)" UserInfo=0x10987e220 {EDAMErrorCode=3, parameter=authenticationToken}
Is there any way to get the userStore from the ENSession? It looks like it's in the .m, but not exposed in the .h. Is there an easy way for me to get access to it from a sharedSession?
When I want to move note into other notebook, I can not use - (void)uploadNote: method in ENSession, because the notebook parameter is not valid when replace.
Do you have plan to integrate the way to move into the notebook, or to allow using the notebook parameter when replace?
The following error occurs intermittently during calls to listNotebooksWithCompletion:
ENSDK ERROR: Error from listSharedNotebooks in business store: Error Domain=ENErrorDomain Code=1 "TTransportException: Could not make HTTP request" UserInfo=0x156db3b0 {NSLocalizedDescription=TTransportException: Could not make HTTP request}
The user is a business user.
My Evernote integrated app (Mars Images) depends on accessing Resource GUID, sourceURL, and cameraModel attributes. ENResource hides or omits all three (presently it only exposes filename and mimetype). Any chance you could make them available from this class, or is my integration better off staying with the "advanced" EDAM API?
Link to my app: https://github.com/OpsLabJPL/MarsImagesIOS
In ENSession.m, the value of businessShardId is never getting set.
we should support iOS 8 and Xcode 6
The function that should be "findRelatedwithQuery" is defined as "findRealtedwithQuery".
It would be great if this new SDK would allow to be used on OSX as a framework. In this case the old and outdated SDK at https://github.com/evernote/evernote-sdk-ios could be completely deprecated!
Setup:
[[ENSession sharedSession] uploadNote:note policy:ENSessionUploadPolicyReplace toNotebook:nil orReplaceNote:noteRef progress:nil completion:^(ENNoteRef *newNoteRef, NSError *error) {
// ...
}];
To display PDF files, need to fix [ENNote generateWebArchiveData:]
we should tell the client if they hit quota limit and inform them when the quota is about to be reached
If you create a notebook with ENNoteStoreClient createNotebook:success:
there is no way to clean a cache used used in listNotebooksWithCompletion:
In ENLoadingViewController you create cancel button using NSLocalizedString
UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Cancel", @"Cancel") style:UIBarButtonItemStylePlain target:self action:@selector(cancel:)];
But in ENOAuthViewController you use NSLocalizedStringFromTable
UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedStringFromTable(@"Cancel", @"EvernoteSDK", nil) style:UIBarButtonItemStylePlain target:self action:@selector(cancel:)];
So when you start loading it uses application Localisable strings, but after it uses localisable strings from EvernoteSDK. Why not to use UIBarButtonSystemItemCancel style? It will be translated by iOS.
I don't sure if this is by design, but currently we have no way to access EDAMNoteAttributes. There is a edamAttributes
field on ENNote but it seems has a different meaning.
After calling the authenticateWithViewController:preferRegistration:completion: method of ENSession class, a corresponding UIViewController appears and presents UIActivityIndicator in centre of view, but this activity indicator keeps spinning forever even if network connection is fine. This prevents user from sign in into Evernote.
Device: iPad mini and iPhone 5
iOS: 7.1.2
When using the ENSaveToEvernoteActivity (on iOS 8), the image in the UIActivityViewController is very hard to see (1st image).
It seems that when using UIActivityCategoryShare (on iOS 8), the icon is placed on the top level and the icon is displayed with its full color. This is in contrast to iOS 7 placing the image on the bottom row with its own rendered image. I tested this by placing the Evernote app icon as the activity image (2nd image).
I would suggest that a different image is used when running on iOS 8.
The cancel method isn't actually implemented for the ENNoteStoreClient. In the THTTPClient.m file the cancel method that it uses is currently this...
(void)cancel {
//noop
}
You'll need to modify that back to what you had in the old sdk (or something similar) if you want it to work.
(void)cancel {
if(self.httpOperation) {
[self.httpOperation cancel];
self.uploadBlock = nil;
self.downloadBlock = nil;
self.httpOperation = nil;
}
}
Then set the self.httpOperation in the flush method of that file and that appears to fix the problem.
I can't seem to figure out how to omit inactive notes from a search...or even filter them from the results.
I feel like I must be missing something, but my review of the search grammar doesn't seem to say anything about it.
I am trying to update notes from the search, and get Note.deleted errors when I hit ones that are in the trash.
Regarding documentation to create business notebook require two steps: create and link the newly created notebook. (https://dev.evernote.com/doc/articles/business.php)
To do get shardId and username for EDAMLinkedNotebook I've made validBusinessAuthenticationResult
method public, but how to do it in "legal" way?
To test operation with Yinxiang Biji, I forced the locale to be "zh_cn". But in ENSession.m > authenticateWithViewController, the call to
[userStore getBootstrapInfoWithLocale:locale success:^(EDAMBootstrapInfo *info)
returns the International www.evernote.com profile in array position 0, and the Chinese Yinxiang profile in array position 1. So then this line:
EDAMBootstrapProfile * profile = [info.profiles objectAtIndex:0];
incorrectly sets the active profile to the International one, instead of the Yinxiang one.
I write an iOS app (Drafts) which has Evernote actions which can create notes, but but also append/prepend text to existing notes.
This is done with the old 1.3 SDK, by downloading the existing note, altering it's content string, and uploading it again.
I just started playing with this new SDK, but I'm not seeing methods to even access the content of a note. I can create new ENContent objects and assign them, but there don't seem to be accessors.
Would it be possible to add methods along the lines of...
ENContent *content = note.content;
note.content = [content contentByAppendingString:(NSString *)string];
note.content = [content contentByPrependingString:(NSString *)string];
(plus similar for sanitizedHTML)?
I'm in a bit of a fix, because I do not wish to continue to use the old SDK, which will not build 64 bit, but this one does not support many basic operations.
Thanks for the feedback!
Sometimes the received SyncChunk has all the fields set to nil, even though there are updates.
Here is the code that checks the sync state and requests the SyncChunk:
NSLog(@"user data getting personal sync state");
[[[ENSession sharedSession] primaryNoteStore] getSyncStateWithSuccess:^(EDAMSyncState *syncState) {
NSLog(@"got personal sync state");
NSInteger lastUpdateCount = [self.personalSyncState.updateCount integerValue];
if (!self.personalSyncState) {
lastUpdateCount = [syncState.updateCount integerValue];
}
NSLog(@"personal sync chunk lastUpdateCount %d, newUpdateCount %d",lastUpdateCount, [syncState.updateCount integerValue]);
BOOL shouldUpdate = [syncState.updateCount integerValue] > lastUpdateCount;
self.personalSyncState = syncState;
if (shouldUpdate) {
EDAMSyncChunkFilter *filter = [self createChunkFilter];
[[[ENSession sharedSession]primaryNoteStore]getFilteredSyncChunkAfterUSN:lastUpdateCount maxEntries:150 filter: filter success:^(EDAMSyncChunk *syncChunk) {
NSLog(@"personal chunk %@",[syncChunk debugDescription]);
[self sendNotification:kMMMEvernotePersonalChunkCollected chunk:syncChunk error:nil];
} failure:^(NSError *error) {
self.lastEvernoteError = error;
[self sendNotification:kMMMEvernotePersonalChunkCollected chunk:nil error:error];
}];
} else {
[self sendNotification:kMMMEvernotePersonalChunkCollected chunk:nil error:nil];
}
} failure:^(NSError *error) {
self.collectedPersonalInformation = YES;
[self setError:error];
[self sendNotification:kMMMEvernotePersonalChunkCollected chunk:nil error:error];
;
}];
Here is the log showing the updateCounts and the returned SyncChunk:
2014-08-25 21:57:26.009 got personal sync state
2014-08-25 21:57:26.009 personal sync chunk lastUpdateCount 377, newUpdateCount 392
2014-08-25 21:57:26.126 personal chunk EDAMSyncChunk: 0x14ec6b40; currentTime = 1409021844038; chunkHighUSN = 392; updateCount = 392; notes = (null); notebooks = (null); tags = (null); searches = (null); resources = (null); expungedNotes = (null); expungedNotebooks = (null); expungedTags = (null); expungedSearches = (null); linkedNotebooks = (null); expungedLinkedNotebooks = (null);
Here is the SyncChunkFilter:
EDAMSyncChunkFilter *filter = [[EDAMSyncChunkFilter alloc]init];
filter.includeNotes = @(YES);
filter.includeNoteAttributes = @(YES);
filter.includeNoteResources = @(NO);
filter.includeNotebooks = @(YES);
filter.includeTags = @(NO);
filter.includeSearches = @(NO);
filter.includeResources = @(NO);
filter.includeLinkedNotebooks = @(YES);
filter.includeExpunged = @(YES);
filter.includeNoteApplicationDataFullMap = @(YES);
filter.includeNoteResourceApplicationDataFullMap = @(NO);
filter.includeResourceApplicationDataFullMap = @(NO);
filter.requireNoteContentClass = @"XXXXXX";
return filter;
Here is the log for a successful sync chunk query in the same session:
2014-08-25 21:53:30.370 got personal sync state
2014-08-25 21:53:30.371 personal sync chunk lastUpdateCount 358, newUpdateCount 359
2014-08-25 21:53:30.515 personal chunk EDAMSyncChunk: 0x14dcf3b0; currentTime = 1409021608405; chunkHighUSN = 359; updateCount = 359; notes = (null); notebooks = (
"EDAMNotebook: 0x14dbfb80; guid = 6a62a30c-51d8-46f5-a07c-b598a3c4bbfc; name = sync test 2; updateSequenceNum = 359; defaultNotebook = 0; serviceCreated = 1409021590000; serviceUpdated = 1409021590000; publishing = (null); published = (null); stack = (null); sharedNotebookIds = (null); sharedNotebooks = (null); businessNotebook = (null); contact = (null); restrictions = EDAMNotebookRestrictions: 0x14dfa880; noReadNotes = (null); noCreateNotes = (null); noUpdateNotes = (null); noExpungeNotes = 1; noShareNotes = (null); noEmailNotes = 1; noSendMessageToRecipients = (null); noUpdateNotebook = (null); noExpungeNotebook = 1; noSetDefaultNotebook = (null); noSetNotebookStack = (null); noPublishToPublic = (null); noPublishToBusinessLibrary = (null); noCreateTags = (null); noUpdateTags = (null); noExpungeTags = 1; noSetParentTag = (null); noCreateSharedNotebooks = (null); updateWhichSharedNotebookRestrictions = (null); expungeWhichSharedNotebookRestrictions = 2; noShareNotesWithBusiness = 1;"
); tags = (null); searches = (null); resources = (null); expungedNotes = (null); expungedNotebooks = (null); expungedTags = (null); expungedSearches = (null); linkedNotebooks = (null); expungedLinkedNotebooks = (null);
To upload notes with some files I use NSURLSession with background configuration. So user don't need to wait until operation finishes. I use TMemoryBuffer to create NSData and then pass it to NSURLSession. The process looks like that:
ENNote -> EDAMNote -> TBinaryProtocol (with TMemoryBuffer) -> NSData -> NSURLSession
In this repository there is no TMemoryBuffer. Is there any way to create NSdata based on ENNote?
When I used ENSession's listNotebooksWithHandler method, EDAMUserException(EDAMErrorCode_DATA_REQUIRED, parameter = shareKeyOrGlobalId) occurred if user has a linked notebook that is public notebook.
The same notebook will be in the notebook list twice when querying linked notebooks, if the permissions have been changed on the notebook by the owner. Both list entries will have a shareKey and getSharedNotebookByAuth fails. The SDK fails in ENSession listNotebooks_processSharedNotebooksWithContext: The log message is displayed: "Error from getSharedNotebookByAuth against a personal linked notebook". The error code =4 and the parameter=SharedNotebook.id
I am trying to set up my app to use the ENSaveToEvernoteActivity as outlined in the docs.
I set the noteTitle and the object I'm passing in is a UIImage.
This is the error I'm getting:
Error Domain=ENErrorDomain Code=2 "The operation couldn’t be completed. (ENErrorDomain error 2.)"
I can’t seem to tease any further info out of the NSError than that, yet. It appears to be bad format, if
I’m looking up the error codes correctly in the docs.
The noteTitle I was trying to save was: "Image RLB_461492641EDR_F0401378RHAZ00325M_ from Curiosity via Mars Images”. I think this conforms to the title regex.
Perhaps EN needs me to do something special with the UIImage?
support cocoapod
[[ENSession sharedSession]findNotesWithSearch:nil inNotebook:linkedNotebook orScope:ENSessionSearchScopeNone sortOrder:ENSessionSortOrderRecentlyUpdated maxResults:50 completion:^(NSArray *findNotesResults, NSError *findNotesError) {
This is the full line I did.
This method returns empty findNotesResults without error.
Hello,
I use EDAMNote to create a note with resource and use ENNoteStoreClient to upload it. In the note content I can't find the Image but it can be seen in the table list.
The resource I created with EDAMResource.
Is it my mistake?
Method listNotebooksWithCompletion:
consist of several requests. If one of those requests failed with an error Completion handler returns the error, but when you use this method second time it returns cached data.
When creating a Business Notebook, the old SDK created the corresponding linked notebook so the user didn't have to go into Evernote and join to the notebook. This new SDK doesn't have that functionality.
Here's what the old SDK had which appears to be missing in the new SDK:
(void)createBusinessNotebook:(EDAMNotebook )notebook
success:(void(^)(EDAMLinkedNotebook *notebook))success
failure:(void(^)(NSError *error))failure {
EvernoteNoteStore businessNoteStore = [EvernoteNoteStore businessNoteStore];
[businessNoteStore createNotebook:notebook success:^(EDAMNotebook businessNotebook) {
EDAMSharedNotebook sharedNotebook = businessNotebook.sharedNotebooks[0];
EDAMLinkedNotebook* linkedNotebook = [[EDAMLinkedNotebook alloc] init];
[linkedNotebook setShareKey:[sharedNotebook shareKey]];
[linkedNotebook setShareName:[businessNotebook name]];
[linkedNotebook setUsername:[[[EvernoteSession sharedSession] businessUser] username]];
[linkedNotebook setShardId:[[[EvernoteSession sharedSession] businessUser] shardId]];
[self createLinkedNotebook:linkedNotebook
success:^(EDAMLinkedNotebook *businessLinkedNotebook) {
success(businessLinkedNotebook);
} failure:^(NSError *error) {
failure(error);
}];
} failure:^(NSError *error) {
failure(error);
}];
}
I really like the abstraction in ENSession
and ENNoteRef
.
However, if I want to access the "advanced API" in ENNoteStoreClient
, I cannot use anything from the simple API. For instance if I have a ENNoteRef
and I would like to get the application data via getNoteApplicationDataWithGuid:success:failure:
, I have to get the appropriate noteStore my self, and find the note GUID (which is not exposed via ENNoteRef).
I wonder if how the cloud SDK envision this ... can we expect the simple API implement each and every API in note store client in future? or simple API is meant to be access only a few method, and rest of them require to use the "Advance API"? Furthermore, what should I do if I'm implementing a client that need to use Advance API today?
Provide delegate in ENSaveToEvernoteActivity so that developers can display 'success' or 'failure' to end users
In the old API we had [[EvernoteNoteStore noteStore] viewNoteInEvernote:note];
which is not available anymore.
See change: 281beac
My app integrates Evernote, but only occasionally uses the integration based on user requests. It does not make sense to make a request whenever the app is launched if Evernote is used only 1 in every few dozen times the users launches my app.
Can this be changed to only be refreshed when need based on Notebook calls? Or this be disabled by flag of some sort?
Thanks.
I'd like to be able to set the attributes for an ENResource, just as you can set an attribute dictionary on ENNote.
Please change the class names of your third party libraries.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.