Pryv iOS/OSX Cocoa SDK
PryvApiKit is an OS X framework and an iOS static library. It handles all networking and interactions with Pryv API for your Objective-C based applications.
**Note PYRequestType Sync / Async will be removed and all request will be made using Async method **
PryvApiKit.framework
This framework Mac OS X lets you interact with the Pryv servers from your Mac OS X application.
First of all, you need to create a WebView object myWebView
that you locate in a window, a panel, a view or whatever you think will be appropriate and make one of your controller a PYWebLoginDelegate
– typically, the WebView controller. You can then obtain your access token with your app ID using the following lines.
NSArray *objects = [NSArray arrayWithObjects:@"*", @"manage", nil];
NSArray *keys = [NSArray arrayWithObjects:@"StreamId", @"level", nil];
NSArray *permissions = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjects:objects forKeys:keys]];
After this preparation, you actually request an access token with these two lines:
[PYClient setDefaultDomainStaging];
[PYWebLoginViewController requestConnectionWithAppId:@"pryv-sdk-osx-example"
andPermissions:permissions
delegate:self
withWebView:&myWebView];
The first one is needed whenever you need to (re-)log a user. Notice in the second method that you pass the reference of your WebView object which will be displayed where you located it asking for username and password. If everything went good, you'll manage the response in the delegate method :
- (void) pyWebLoginSuccess:(PYConnection*)pyConnection {
NSLog(@"Signin With Success %@ %@",pyConnection.userID,pyConnection.accessToken);
[pyConnection synchronizeTimeWithSuccessHandler:nil errorHandler:nil];
}
Otherwise, you can manage abortion and error using the methods - (void) pyWebLoginAborted:(NSString*)reason
and - (void) pyWebLoginError:(NSError*)error
.
LibPryvApiKit.a
This is a static library to be used for iOS. Usage is pretty straightforward. First of all, you need to obtain access token. To achieve this, you should set up a permission array in which you specify what streams you need and what access for those streams you ask for, like this :
NSArray *objects = [NSArray arrayWithObjects:@"*", @"manage", nil];
NSArray *keys = [NSArray arrayWithObjects:@"StreamId", @"level", nil];
NSArray *permissions = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjects:objects forKeys:keys]];
After this preparation, you actually request for an access token using this method :
[PYClient setDefaultDomainStaging];
[PYWebLoginViewController requestConnectionWithAppId:@"pryv-sdk-ios-example"
andPermissions:permissions
delegate:self];
The first line is needed whenever you need to (re-)log a user. Here you are sending the appId
and an array of permissions. An instance of UIWebView
will pop up and will ask the user for username and password. If everything went ok, you'll get response in the delegate method.
- (void) pyWebLoginSuccess:(PYConnection*)pyConnection {
NSLog(@"Signin With Success %@ %@",pyConnection.userID,pyConnection.accessToken);
[pyConnection synchronizeTimeWithSuccessHandler:nil errorHandler:nil];
}
Otherwise, you can manage abortion and error using the methods - (void) pyWebLoginAborted:(NSString*)reason
and - (void) pyWebLoginError:(NSError*)error
.
PryvApiKit
Compatible with iOS and Mac OS X.
Inits
FIXME
/** refresh stream list **/
[connection refreshStreams:^done]
Calls
FIXME
/** get latest stream structure fetched **/
NSArray *currentStreams = connection.currentStreams;
Notifications
PYConnection
-
name: "EVENTS" userInfo
-
name: "EVENTS"
userInfo
NSDictionary = @{ kPYNotificationKeyAdd : NSArray of PYEvents, kPYNotificationKeyModify : ... kPYNotificationKeyDelete : ... }
- name: "STREAMS" userInfo
NSArray of (root) PYStreams
complete structure of streams is accessible thru childrens
- name: "LOADING" userInfo
NSDictionary = @{ kPYNotificationKeyAdd : @"BEGIN" or @"END", @"CALL" : @"STREAMS" or kPYNotificationEvents or @"PROFILE" ... (API key) }
PYFilter
- name: "EVENTS"
userInfo
NSDictionary = @{ kPYNotificationKeyAdd : NSArray of PYEvents,
kPYNotificationKeyModify : ...
kPYNotificationKeyDelete : ... }
streams
[[NSNotificationCenter defaultCenter] addObserverForName:@"STREAMS"
object:connection
queue:nil
usingBlock:^(NSNotification *note) {
NSDictionary *message = (NSDictionary*) note.userInfo;
NSArray *streams = [message objectForKey:@"STREAMS"];
//...
}];
// shortcut for the above
[connection addObserverForStreams:^(NSArray *streams) {
// ...
}];
events
PYEventFilter* pyFilter = [[PYEventFilter alloc] initWithConnection:self.connection
fromTime:PYEventFilter_UNDEFINED_FROMTIME
toTime:PYEventFilter_UNDEFINED_TOTIME
limit:20
onlyStreamsIDs:nil
tags:nil];
[[NSNotificationCenter defaultCenter] addObserverForName:kPYNotificationEvents
object:pyFilter
queue:nil
usingBlock:^(NSNotification *note)
{
NSDictionary *message = (NSDictionary*) note.userInfo;
NSArray *toAdd = [message objectForKey:kPYNotificationKeyAdd];
if (toAdd && toAdd.count > 0) {
NSLog(@"ADD %i", toAdd.count);
}
NSArray *toRemove = [message objectForKey:kPYNotificationKeyDelete];
if (toRemove) {
NSLog(@"REMOVE %i", toRemove.count);
}
NSArray *modify = [message objectForKey:kPYNotificationKeyModify];
if (modify) {
NSLog(@"MODIFY %i", modify.count);
}
}]
// shortcut with the same effect than previous code
[pyFilter addObserverForEvents:^(NSArray *toAdd, NSArray *modify, NSArray *toRemove) { ... }]
[pyFilter refresh]; // refresh once
[pyFilter autoRefresh:30000]; // time in miliseconds
Main Methods
The user ID and the access token are used for creating PYConnection object.
PYConnection *access = [PYClient createAccessWithUsername:@"username" andAccessToken:@"accessToken"];
With PYConnection
objects, you can browse Streams, streams and events with the permissions you have in access token.
[Connection getAllStreamsWithRequestType:PYRequestTypeAsync gotCachedStreams:^(NSArray *cachedStreamList) {
} gotOnlineStreams:^(NSArray *onlineStreamList) {
} errorHandler:^(NSError *error) {
}];
This library can work offline if caching is enabled. To enable/disable caching possibility you set the preprocessor macro CACHE
in project file to 1/0 depending on whether or not you want caching support.
cachedStreamList
and onlineStreamList
contain PYStream
objects. A Stream il linked to PYStream
children and PYEvent
objects.
You can manipulate streams and events. For example, you can create, delete, modify, …. Same rules applie for other object types. Currently only personal type of access allows creating Streams and it will be added for v2 of SDK when access-rights will be covered in depth.
PYConnection
methods:
Some useful Example of getting all events:
filter:nil
means no filer, so all events.
[connection getEventsWithRequestType:PYRequestTypeAsync filter:nil
gotCachedEvents:^(NSArray *cachedEventList) {
} gotOnlineEvents:^(NSArray *onlineEventList) {
} successHandler:^(NSArray *eventsToAdd, NSArray *eventsToRemove, NSArray *eventModified) {
} errorHandler:^(NSError *error) {
}];
Example of creating event on server:
PYEvent *event = [[PYEvent alloc] init];
event.streamId = @"someStreamId";
event.value = @"someEventValue";
event.eventClass = @"note";
event.eventFormat = @"txt";
event.tags = @[@"tag1", @"tag2", @"tag3"];
event.clientData = @{@"clDataKey": @"clientDataObject"};
[connection createEvent:event
requestType:PYRequestTypeAsync
successHandler:^(NSString *newEventId, NSString *stoppedId) {
} errorHandler:^(NSError *error) {
}];
Example of modifying event data on server. You create an event object with the properties you want to modify. In the example below, we are sending events with id "someEventId" to stream with id "someStreamId" and we are changing event value
property.
PYEvent *event = [[PYEvent alloc] init];
event.streamId = @"someStreamId";
event.value = @"someEventValue";
[connection updateEvent:event
successHandler:^(NSString *stoppedId) {
} errorHandler:^(NSError *error) {
}];
Example of getting events from server with filter. This particular filter will search for events recorded in the last 60 days, ones that are in specific streamId
and tagged with tag2
. List of events will be limited to 10 results. If caching is enabled for library it will automatically sync events with ones from cache and give you result of synchronization.
NSDate *today = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:-60];
NSDate *fromTime = [cal dateByAddingComponents:components toDate:today options:0];
NSDate *toTime = today;
PYEventFilter *eventFilter = [[PYEventFilter alloc] initWithConnection:connection
fromTime:[fromTime timeIntervalSince1970]
toTime:[toTime timeIntervalSince1970]
limit:10
onlyStreamsIDs:@[@"streamId"]
tags:@[@"tag2"]];
[eventFilter getEventsWithRequestType:PYRequestTypeSync gotCachedEvents:^(NSArray *eventList) {
NSLog(@"cached eventList %@",eventList);
} gotOnlineEvents:^(NSArray *eventsToAdd, NSArray *eventsToRemove, NSArray *eventModified) {
NSLog(@"eventsToAdd %@",eventsToAdd);
NSLog(@"eventsToRemove %@",eventsToRemove);
NSLog(@"eventModified %@",eventModified);
} errorHandler:^(NSError *error) {
NSLog(@"error is %@",error);
}];
In a similar way, you manipulate streams.
Getting all streams from current Stream:
[connection getAllStreamsWithRequestType:PYRequestTypeAsync
filterParams:nil
gotCachedStreams:^(NSArray *cachedStreamsList) {
} gotOnlineStreams:^(NSArray *onlineStreamList) {
} errorHandler:^(NSError *error) {
}];
Creating stream in current Stream:
PYStream *stream = [[PYStream alloc] init];
stream.name = @"someStreamName";
[connection createStream:stream withRequestType:PYRequestTypeAsync successHandler:^(NSString *createdStreamId) {
} errorHandler:^(NSError *error) {
}];
If you want to change name of previously created stream above, you do this :
PYStream *stream = [[PYStream alloc] init];
stream.name = @"someStreamNameChanged";
[connec setModifiedStreamAttributesObject:stream
forStreamId:createdStreamId
requestType:PYRequestTypeAsync successHandler:^{
} errorHandler:^(NSError *error) {
}];
You can trash/delete stream in this way:
[connection trashOrDeleteStreamWithId:createdStreamId filterParams:nil withRequestType:PYRequestTypeAsync successHandler:^{
} errorHandler:^(NSError *error) {
}];
Some words about caching
If caching is enabled for library, Streams, streams or events requested from server will be cached automatically. If you want to create an event and you get successful response, that event will be cached automatically for you. Same rules apply for other types. If you are offline, the library still works. All Streams, streams or events will be cached on disk with tempId and will be put in unsync list. When internet turns on, the unsync list will be synched with server and all events, streams or Streams will be cached automatically. Developers don't need to care about caching, all process about it is done in background. Developers should use public API methods as usual. From my pov I'll rather take out gotCachedStreams
gotCachedEvents
and gotCachedStreams
callbacks because I think it's unnecessary. Everything can be in one callback… Perki, what do you think about it?
Also, there are some testing classes that are testing whether or not Objective-C public API works with web service. To perform those tests start iOS example in simulator first. After this step, stop the simulator and choose libPryvApiKit.a scheme. Go to Product->Test in xCode.
Use cases
Editing an event with an eventual rollback
event.isDraft
(ie event.hasTempId && !event.toBeSync
)
If the event is a draft - Rollback: Event just have to be thrown away in case of cancel.
- Save:
[connection createEvent:event ......]
If the event is not a draft, the properties of the event have been cached.
- Rollback:
[event resetFromCache]
- Save:
[connection updateEvent:event ......]
Note: there is a fallback with this method. Until data is reset changes are done on app-wide instance of the event. We may at some point need a logic with PYEvent *backupEvent = [event backup] ; [event restoreFromBackup:backupEvent]