Spotify New iOS SDK (SPTRemoteApp and SPTSessionManger) in iOS - ios

As Spotify framework is upgraded and new classes like SPTRemoteApp has
been introduced, I got totally frustrated to integrate it in old app
as they have changed almost every thing. So I need help if someone can
tell me these following points how it works. Somehow I feel I can do
login part but about track list and its playback part seems not
properly understandable from the Spotify developer docs for iOS.
How to get login Url from new Spotify framework or how to login by clicking button without checking login URL content.
How to get playlist like previously we get playlist by calling this method
[SPTRequest playlistsForUserInSession:session callback:^(NSError *error, SPTListPage *object) {
playListCount = [object.items count] - 1;
if (object.items) {
[object.items enumerateObjectsUsingBlock:^(SPTPartialPlaylist *obj, NSUInteger idx, BOOL *stop) {
[playlistURI addObject:obj.uri];
if (idx == object.items.count - 1) {
[weakSelf requestsTracks:playlistURI withSession:session];
}
spotifySynching = NO;
}];
}else{
spotifySynching = NO;
[self stopAnimatingTotalSpinner];
[self updateProgressDisplays];
}
}];
How to maintain and renew session, nd when we should renew it.
What is the replacement of these methods
(SPTListPage *)object;
[object requestNextPageWithSession:session callback:^(NSError *error, SPTListPage *object) {
[tracksURI addObjectsFromArray:object.items];
if ([object hasNextPage]) {
[self hasNextTrack:object withSession:session withNewObject:newObject];
}else{
[self requestsTracks:newObject withSession:session];
}
}];
[SPTRequest requestItemAtURI:obj withSession:session callback:^(NSError *error, SPTPlaylistSnapshot *object) {
if (error != nil) {
NSLog(#"*** Auth error: %#", error);
return;
}
[tracksURI addObjectsFromArray:object.firstTrackPage.items];
if ([object.firstTrackPage hasNextPage]) {
[self hasNextTrack:object.firstTrackPage withSession:session withNewObject:newObject];
}else{
[self requestsTracks:newObject withSession:session];
}
}];
Please check and let me know.
Thanks

Related

Optimistic concurrency in Azre iOS client SDK

I have a query regarding concurrency in Azure mobile client SDK.
for windows I found Conflict link for handling concurrency but I could not found the same for iOS client SDK.
Can anyone please suggest or help how to handle concurrency in iOS client SDK.
Here is the old Mobile Services page for handling conflicts with the iOS SDK. The setup for offline sync with the iOS SDK hasn't changed since then.
1) Set up an MSSyncContextDelegate and pass it to the MSSyncContext constructor when you create it.
2) Implement tableOperation:(MSTableOperation *)operation onComplete:(MSSyncItemBlock)completion in your delegate. After executing the operation, check for an MSErrorPreconditionFailed error code and decide what to do from there based on your app's needs.
- (void)tableOperation:(MSTableOperation *)operation onComplete:(MSSyncItemBlock)completion
{
[operation executeWithCompletion:^(NSDictionary *item, NSError *error) {
NSDictionary *serverItem = [error.userInfo objectForKey:MSErrorServerItemKey];
if (error.code == MSErrorPreconditionFailed) {
QSUIAlertViewWithBlock *alert = [[QSUIAlertViewWithBlock alloc] initWithCallback:^(NSInteger buttonIndex) {
if (buttonIndex == 1) { // Client
NSMutableDictionary *adjustedItem = [operation.item mutableCopy];
[adjustedItem setValue:[serverItem objectForKey:MSSystemColumnVersion] forKey:MSSystemColumnVersion];
operation.item = adjustedItem;
[self doOperation:operation complete:completion];
return;
} else if (buttonIndex == 2) { // Server
NSDictionary *serverItem = [error.userInfo objectForKey:MSErrorServerItemKey];
completion(serverItem, nil);
} else { // Cancel
[operation cancelPush];
completion(nil, error);
}
}];
NSString *message = [NSString stringWithFormat:#"Client value: %#\nServer value: %#", operation.item[#"text"], serverItem[#"text"]];
[alert showAlertWithTitle:#"Server Conflict"
message:message
cancelButtonTitle:#"Cancel"
otherButtonTitles:[NSArray arrayWithObjects:#"Use Client", #"Use Server", nil]];
} else {
completion(item, error);
}
}];
}

iOS 'reportAchievementWithCompletionHandler' deprecated

A part of code (I didn't write) is shown as deprecated in my Xcode project, here's the code block:
#pragma mark - Report Achievement Progress
static int reportAchievement(struct lua_State *state) {
[gameCenterAddOnInstance reportAchievementAction:[NSString stringWithCString:lua_tostring(state, 1) encoding:NSUTF8StringEncoding] percentComplete:(int)lua_tointeger(state, 2)];
return 1;
}
- (void) reportAchievementAction: (NSString*) identifier percentComplete: (float) percent
{
GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier: identifier];
if (achievement)
{
achievement.percentComplete = percent;
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error != nil)
{
NSLog(#"Error in reporting achievements: %#", error);
}
}];
}
}
According to Xcode, the depreciated part is:
reportAchievementWithCompletionHandler
Xcode suggests to use:
reportAchievements:WithCompletionHandler:
Instead. But, not being familiar with objective C, I wouldn't know where to start.
How to implement to new function?
Try this
[GKAchievement reportAchievements:#[achievement] withCompletionHandler:^(NSError *error)
{
if (error != nil)
{
NSLog(#"Error in reporting achievements: %#", error);
}
}];
Apple replaced the instance method - reportAchievementWithCompletionHandler: with the class method + reportAchievements:withCompletionHandler:. This allows you to report multiple achievements at once without having to call the instance method on every achievement object.
#[achievement] is shorthand for [NSArray arrayWithObjects:achievement, nil].

linkUserInBackground return succeeded as NO

I have a very strange behaviours with one user when trying to post. (ipad 2, ios8.3, parse 1.7.4)
(from my device, all ok).
bGranted_publish_actions = always false
bGranted_user_photos = always false
When I call linkUserInBackground, i can see the facebook app opening(very long), and then close directly(not event the time to see the permission screen), and my ios app reopen.
error=nil
succeeded= no
Any idea?
-(void)postShareToFacebookWithDescription:(NSString *)description andBlock:(void (^)(NSError *))completionBlock{
NSLog(#"ℹ️--[%s:%d]",__PRETTY_FUNCTION__,__LINE__);
bool bGranted_publish_actions=[[FBSDKAccessToken currentAccessToken] hasGranted:#"publish_actions"];
bool bGranted_user_photos=[[FBSDKAccessToken currentAccessToken] hasGranted:#"user_photos"];
if (!bGranted_user_photos || !bGranted_publish_actions ){
//withPublishPermissions:#[#"publish_actions", #"user_photos"
[PFFacebookUtils linkUserInBackground:[PFUser currentUser] withPublishPermissions:#[#"publish_actions"] block:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"User now has read and publish permissions!");
[self postDataWithPhoto:nil];
} else {
if (completionBlock) {
completionBlock(error);
}
}
}];
} else {
NSLog(#"Got Facebook publish permissions and about to share");
[self postDataWithPhoto:nil];
}
}
I got my answer:
FBSDKLoginManager logInWithPublishPermissions always returns isCancelled=YES
"This can happen when your Facebook App doesn't have "publish_actions"
permission, or you're not using a test user."

Firebase: Is there way to be more faster for authentication?

Similar to this question. Is it possible to cache the auth token to speed up login in Firebase with iOS?
I'm authenticating with FirebaseSimpleLogin. Here is my authentication code
- (void)checkAuthStatus{
Firebase *ref = [[Firebase alloc] initWithUrl:rootURL];
FirebaseSimpleLogin *authClient = [[FirebaseSimpleLogin alloc] initWithRef:ref];
[authClient checkAuthStatusWithBlock:^(NSError *error, FAUser *user)
{
if (error == nil)
{
if (user != nil)
{
if(user.thirdPartyUserData == nil){
//Email Login
}else{
//Facebook、Twitter Login
}
}else [self actionLogin];
}
else
{
NSString *message = [error.userInfo valueForKey:#"NSLocalizedDescription"];
[self performSelectorOnMainThread:#selector(showError:) withObject:message waitUntilDone:NO];
}
}];
}
I also this method with async blocks
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self checkAuthStatus];
});
This takes around 5 - 8 seconds until showing tableview data source.
I tried to run iFirefeed app but it takes almost same time.
I want to know more faster way if there is.
Anyone have idea or experience to be more faster for authentication?

iOS GameCenter GKErrorCanceled

I'm in sandbox mode implementing game center in my application. The problem comes when I log to gameCenter, in some devices works fine in some others I get a GKErrorCanceled without even get the interface shown.
This devices don't have any user logged in gameCenter so it's not related to have a non sandbox account logged. My code is:
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
//First we try the new iOS6 authentification method for gamekit, if it's not implemented we will use the deprecated one
if ([localPlayer respondsToSelector:#selector(setAuthenticateHandler:)]) {
if (localPlayer.isAuthenticated) {
this->setState(connectionLoged);
this->getDelegate().socialConnectionDidSucceedLogin(*this);
return;
}
else if(!localPlayer.isAuthenticated && localPlayer.authenticateHandler){
this->setState(connectionClosed);
this->getDelegate().socialConnectionDidFailToLogin(*this, std::string("The user already resign to login"));
return;
}
else{
localPlayer.authenticateHandler = ^(UIViewController* viewController, NSError* error){
if (localPlayer.isAuthenticated)
{
_name = [localPlayer.displayName UTF8String];
_userId = [localPlayer.playerID UTF8String];
[GKPlayer loadPlayersForIdentifiers:localPlayer.friends withCompletionHandler:^(NSArray *players, NSError *error) {
for (GKPlayer* player in players) {
if ([player isFriend]) {
NSDictionary* dict =
#{#"displayName" : player.displayName,
#"alias" : player.alias,
#"playerID" : player.playerID};
AttrDictionary* playerInfo = [dict hydraAttrDictionary];
SocialFriend* socialfriend = this->getNewFriendInstance(*playerInfo);
this->addFriend(socialfriend);
delete playerInfo;
}
}
this->getDelegate().socialConnectionDidSucceedLogin(*this);
this->setState(connectionLoged);
}];
}
else if(viewController){
UIViewController* rootViewController = (UIViewController*) [UIApplication sharedApplication].keyWindow.rootViewController ;
[rootViewController presentModalViewController:viewController animated:YES];
}
else{
if(error){
this->getDelegate().socialConnectionDidFailToLogin(*this, std::string([error.description UTF8String]));
}
else{
this->getDelegate().socialConnectionDidFailToLogin(*this, std::string("User cancelled login"));
}
}
};
}
}
//deprecated at IOs 6 authentification method
else
[localPlayer authenticateWithCompletionHandler:^(NSError *error) {
if (localPlayer.isAuthenticated)
{
_name = [localPlayer.displayName UTF8String];
_userId = [localPlayer.playerID UTF8String];
[GKPlayer loadPlayersForIdentifiers:localPlayer.friends withCompletionHandler:^(NSArray *players, NSError *error) {
for (GKPlayer* player in players) {
if ([player isFriend]) {
NSDictionary* dict =
#{#"displayName" : player.displayName,
#"alias" : player.alias,
#"playerID" : player.playerID};
AttrDictionary* playerInfo = [dict hydraAttrDictionary];
SocialFriend* socialfriend = this->getNewFriendInstance(*playerInfo);
this->addFriend(socialfriend);
delete playerInfo;
}
}
this->getDelegate().socialConnectionDidSucceedLogin(*this);
this->setState(connectionLoged);
}];
}
else{
NSString* errorString = [error localizedDescription];
this->getDelegate().socialConnectionDidFailToLogin(*this, std::string([errorString UTF8String]));
this->setState(connectionClosed);
}
}];
I need the code compatible with iOS 6 and iOS 5 so you will see I have the two implementations. For iOS 6 the completion handler returns with an UIViewController null and the error as I say. I'm afraid that in production it happends the same. In the simulator all works fine.
PS- You will find some c++ code, it's because I implement a c++ wrapper for GameCenter as my game is write in cocos2dx...
When someone cancels out of the interface to sign in to game center, it will give you GKErrorCanceled. The third time in a row that they cancel, it will warn them that it will disable game center.
If they do choose to disable game center, then it won't show the interface anymore, and it will just give you GKErrorCanceled instead.
Once game center has been disabled, the only way to sign in is by going into the actual game center app.
The 3 times in a row could be in any app or any combination of apps that use game center, and game center will be disabled for all apps that use game center. The 3 times in a row restarts every time they sign in to game center.
This is for both sandbox and non-sandbox.
This is for both ios 5 and ios 6.

Resources