I'm completely new to development in Game Center. I have watched the videos in WWDC and looked at the developer website. They suggest I enter code like this for iOS 6:
- (void) authenticateLocalPlayer
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil)
{
[self showAuthenticationDialogWhenReasonable: viewController
}
else if (localPlayer.isAuthenticated)
{
[self authenticatedPlayer: localPlayer];
}
else
{
[self disableGameCenter];
}
}];
}
I have copied this into the app delegate.m file, however it does not like it, showing errors like expecting a ] after [self showAuthenticationDialogWhenReasonable: viewController
} amongst others.
Can anyone please tell me how to authenticate the user for game center in iOS 6?
To get an introduction to GameKit, there are samples available from apple, for example:
https://developer.apple.com/library/ios/#samplecode/GKLeaderboards/Introduction/Intro.html.
In your code you are missing the closing "]", but of course you need more than just this function to connect to the gameCenter. Best start with one of the samples.
Apple has posted incorrect code, the ]; towards the end of the code belongs at the end of this line [self showAuthenticationDialogWhenReasonable: viewController
this code is not needed because this is just explaining how the method authenticateLocalPlayer works inside of Gamekit
Here's what I did without having to use the deprecated methods:
Set the authentication handler immediately in the AppDelegate by calling the function below (I put it in a singleton helper object). At this time, there is no view controller from which to show the login view controller, so if authentication fails, and the handler gives you a view controller, just save it away. This is the case when the user is not logged in.
- (void)authenticateLocalUserNoViewController {
NSLog(#"Trying to authenticate local user . . .");
GKLocalPlayer *_localPlayer = [GKLocalPlayer localPlayer];
__weak GKLocalPlayer *localPlayer = _localPlayer; // Avoid retain cycle inside block
__weak GCHelper *weakself = self;
self.authenticationViewController = nil;
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error)
{
if (viewController) {
NSLog(#"User not logged in");
weakself.authenticationViewController = viewController; // save it away
} else if (localPlayer.authenticated) {
[[GKLocalPlayer localPlayer] unregisterListener:self];
[[GKLocalPlayer localPlayer] registerListener:self];
NSLog(#"Local player %# (%#) authenticated. ID = %#",localPlayer.alias, localPlayer.displayName, localPlayer.playerID);
} else {
// Probably user cancelled the login dialog
NSLog(#"Problem authenticating %#", [error localizedDescription]);
}
};
}
Then, once your main screen has loaded, and the user wants to press a button the start an online game, present the login view controller that you stashed away earlier. I put this in another method in my helper class. When the user logs in, it will trigger an execution of your original authentication block, but the viewcontroller parameter will be nil.
-(BOOL) showGameCenterLoginController:(UIViewController *)presentingViewController {
if (self.authenticationViewController) {
[presentingViewController presentViewController:self.authenticationViewController animated:YES completion:^{
}];
return YES;
} else {
NSLog(#"Can't show game center view controller!");
return NO; // Show some other error dialog like "Game Center not available"
}
}
Related
I do not have a working version or idea how to get photos from your albums via PHPhotoLibrary or ALAssetsLibrary and install them in uicollectionviewcell like in instagram. I'm new to objective c :)
not install - add
I'm not sure what you mean by 'install to uicollectionviewcell' but here's how you would get photos from your album.
Ask for authorization
Show a UIImagePickerController (which is the default image picker view apple created for us)
Implement delegate methods to handle the picked image from the UIImagePickerController
Code would look as follows
Import statement:
#import <Photos/Photos.h>
Instantiate the image picker controller to show:
UIImagePickerController* imagePicker = [[UIImagePickerController alloc]init];
// Check if image access is authorized
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// Use delegate methods to get result of photo library -- Look up UIImagePicker delegate methods
imagePicker.delegate = self;
[self presentViewController:imagePicker animated:true completion:nil];
}
I believe this would usually prompt the user for access to the photo library, but it's always good practice to handle all cases of authorization prior to simply trying to show the imagepicker.
Ask for authorization:
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if(status == PHAuthorizationStatusNotDetermined) {
// Request photo authorization
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
// User code (show imagepicker)
}];
} else if (status == PHAuthorizationStatusAuthorized) {
// User code
} else if (status == PHAuthorizationStatusRestricted) {
// User code
} else if (status == PHAuthorizationStatusDenied) {
// User code
}
Finally implement delegate methods:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = info[UIImagePickerControllerOriginalImage];
// Do something with picked image
}
After you pick your image, you can add it to a newly instantiated UICollectionViewController. This is probably a whole other question and you would be better off reading documentation for this.
Note that this was introduced in IOS8(I think?), but the AL route code will be similar to the above.
Added
The photo library is just another database, but you still have to ask the user for authorization.
The steps would be as follows:
Ask for authorization
Retrieve photos from photo library
I haven't done #2 myself but there seems to be a way to do it.
Get all of the pictures from an iPhone photoLibrary in an array using AssetsLibrary framework?
From a cursory look, it seems like this is an asynchronous function so you should code accordingly (I would call the requestImage function inside each UICollectionViewCell if I were you).
Leave a comment if you run into any trouble.
Good Luck!
You need to declare delegate UIImagePickerControllerDelegate
like this..
hope its helps you a lot...
- (IBAction)captureImagehandler:(id)sender
{
if (! [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIAlertView *deviceNotFoundAlert = [[UIAlertView alloc] initWithTitle:#"No Device" message:#"Camera is not available"
delegate:nil
cancelButtonTitle:#"exit"
otherButtonTitles:nil];
[deviceNotFoundAlert show];
}
else
{
UIImagePickerController *cameraPicker = [[UIImagePickerController alloc] init];
cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraPicker.delegate =self;
// Show image picker
[self presentViewController:cameraPicker animated:YES completion:nil];
}
}
I am integrating game center on cocos2d project.
GKLeaderboardViewController* leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != nil){
NSLog(#"view make");
leaderboardController.leaderboardDelegate = self;
leaderboardController.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardController.category = #"myGameBoard";
[[CCDirector sharedDirector] presentViewController: leaderboardController animated: YES completion:nil];
show popup
Game Center unavailable
Player is not signed in
and no leaderboard appeared.
My Conditions are
1)testuser looks successfully loginnd
this message appeared on screen.
Welcome back testuser
*** sandbox ***
2)then this message appeared
Game Center unavailable
Player is not signed in
3)App upload is ready and pass the validate on organizer
4)app version on itunes connect and local is the same 1.00
5)Bundle Idenfier on itunes connect and local is the same
6)leaderboardController.category name 'myGameBoard' is correctly set.
is there any other point I need to investigate??
I solved this problem for TEST MODE in this way:
Go to Game Center App
Tab Friends
Click Setting
at the end of the screen: SANDBOX and LOGGING MUST BE ON MODE
I hope that it works for everyone
I solved this issue by ensuring the local user was authenticated and logged in:
- (void) authenticateLocalUser
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
if (![localPlayer isAuthenticated])
{
[localPlayer setAuthenticateHandler:(^(UIViewController* viewcontroller, NSError *error) {
if (!error && viewcontroller)
{
AppDelegate *appDelegate = (AppDelegate*) [[UIApplication sharedApplication] delegate];
UIViewController *currentViewController = [[appDelegate window] rootViewController];
[currentViewController presentViewController:viewcontroller animated:YES completion:nil];
}
})];
}
}
I have a settings view where the user can choose switch on or off the feature 'Export to Camera Roll'
When the user switches it on for the first time (and not when he takes the first picture), I would like the app to ask him the permission to access the camera roll.
I've seen behavior in many app but can't find the way to do it.
I'm not sure if there is some build in method for this, but an easy way would be to use ALAssetsLibrary to pull some meaningless bit of information from the photo library when you turn the feature on. Then you can simply nullify what ever info you pulled, and you will have prompted the user for access to their photos.
The following code for example does nothing more than get the number of photos in the camera roll, but will be enough to trigger the permission prompt.
#import <AssetsLibrary/AssetsLibrary.h>
ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
NSLog(#"%zd", [group numberOfAssets]);
} failureBlock:^(NSError *error) {
if (error.code == ALAssetsLibraryAccessUserDeniedError) {
NSLog(#"user denied access, code: %zd", error.code);
} else {
NSLog(#"Other error code: %zd", error.code);
}
}];
EDIT: Just stumbled across this, below is how you can check the authorization status of your applications access to photo albums.
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
if (status != ALAuthorizationStatusAuthorized) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Attention" message:#"Please give this app permission to access your photo library in your settings app!" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil, nil];
[alert show];
}
Since iOS 8 with Photos framework use:
Swift 3.0:
PHPhotoLibrary.requestAuthorization { status in
switch status {
case .authorized:
<#your code#>
case .restricted:
<#your code#>
case .denied:
<#your code#>
default:
// place for .notDetermined - in this callback status is already determined so should never get here
break
}
}
Objective-C:
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
switch (status) {
case PHAuthorizationStatusAuthorized:
<#your code#>
break;
case PHAuthorizationStatusRestricted:
<#your code#>
break;
case PHAuthorizationStatusDenied:
<#your code#>
break;
default:
break;
}
}];
Important note from documentation:
This method always returns immediately. If the user has previously granted or denied photo library access permission, it executes the handler block when called; otherwise, it displays an alert and executes the block only after the user has responded to the alert.
Since iOS 10, we also need to provide the photo library usage description in the info.plist file, which I described there. And then just use this code to make alert appear every time we need:
- (void)requestAuthorizationWithRedirectionToSettings {
dispatch_async(dispatch_get_main_queue(), ^{
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusAuthorized)
{
//We have permission. Do whatever is needed
}
else
{
//No permission. Trying to normally request it
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status != PHAuthorizationStatusAuthorized)
{
//User don't give us permission. Showing alert with redirection to settings
//Getting description string from info.plist file
NSString *accessDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"NSPhotoLibraryUsageDescription"];
UIAlertController * alertController = [UIAlertController alertControllerWithTitle:accessDescription message:#"To give permissions tap on 'Change Settings' button" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:nil];
[alertController addAction:cancelAction];
UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:#"Change Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}];
[alertController addAction:settingsAction];
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
}
}];
}
});
}
Also, there are some common cases when the alert doesn't appear. To avoid copying I would like you to take a look at this answer.
The first time the user tries to write to camera roll on ios 6 he/she is automatically asked for permission. You don't have to add extra code (before that the authorisationstatus is ALAuthorizationStatusNotDetermined ).
If the user denies the first time you cannot ask again (as far as I know). The user has to manually change that app specific setting in the settings->privacy-> photos section.
There is one other option and that is that it the user cannot give permission due other restrictions like parental control, in that case the status is ALAuthorizationStatusRestricted
Swift:
import AssetsLibrary
var status:ALAuthorizationStatus = ALAssetsLibrary.authorizationStatus()
if status != ALAuthorizationStatus.Authorized{
println("User has not given authorization for the camera roll")
}
#import <AssetsLibrary/AssetsLibrary.h>
//////
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
switch (status) {
case ALAuthorizationStatusRestricted:
{
//Tell user access to the photos are restricted
}
break;
case ALAuthorizationStatusDenied:
{
// Tell user access has previously been denied
}
break;
case ALAuthorizationStatusNotDetermined:
case ALAuthorizationStatusAuthorized:
// Try to show image picker
myPicker = [[UIImagePickerController alloc] init];
myPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
myPicker.delegate = self;
[self presentViewController: myPicker animated:YES completion:NULL];
break;
default:
break;
}
iOS 9.2.1, Xcode 7.2.1, ARC enabled
'ALAuthorizationStatus' is deprecated: first deprecated in iOS 9.0 -
Use PHAuthorizationStatus in the Photos framework instead
Please see this post for an updated solution:
Determine if the access to photo library is set or not - PHPhotoLibrary (iOS 8)
Key notes:
Most likely you are designing for iOS7.0+ as of todays date, because of this fact you will need to handle both ALAuthorizationStatus and PHAuthorizationStatus.
The easiest is to do...
if ([PHPhotoLibrary class])
{
//Use the Photos framework
}
else
{
//Use the Asset Library framework
}
You will need to decide which media collection you want to use as your source, this is dictated by the device that your app. will run on and which version of OS it is using.
You might want to direct the user to settings if the authorization is denied by user.
In my app i want let user to control audio playback in background. I set backGround modes in .plist, and in plays in bg just like i wanted.But i can't get any response from touching the control buttons.
I set the AudioSession like this
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance]setActive:YES error:nil];
Then, in viewContoller where my player is placed i beginReceivingRemoteControlEvents like this
if ([[UIApplication sharedApplication] respondsToSelector:#selector(beginReceivingRemoteControlEvents)]){
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
[self becomeFirstResponder];
NSLog(#"Responds!");
}
And it prints Responds!
But the problem is that this method is never called
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
{
NSLog(#"Where is my event?");
if(event.type == UIEventTypeRemoteControl)
{
switch (event.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
NSLog(#"Pause");
[self playWords:playButton];
break;
case UIEventSubtypeRemoteControlNextTrack:
NSLog(#"Next");
[self next];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
NSLog(#"Prev");
[self prev];
break;
}
}
I even tried to write a category on UIApplication to let it become the first responder, but it doesn't help
#implementation UIApplication (RemoteEvents)
-(BOOL)canBecomeFirstResponder
{
return YES;
}
#end
Why can this happen?
SOLUTION
Here's what solved my problem Entering background on iOS4 to play audio
I have done the same work in my project, it's working fine. Please follow this, perhaps it will help you. Change the event name etc. In my code _audio is the object of AVAudioPlayer.
- (void)viewDidLoad {
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryErr];
[[AVAudioSession sharedInstance] setActive: YES error: &activationErr];
}
- (void)viewWillAppear {
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
[_audio play];
break;
case UIEventSubtypeRemoteControlPause:
[_audio pause];
break;
default:
break;
}
}
There is a newer mechanism for listening to remote control events. For example, to execute a block when the headphone play/pause button is pressed:
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[commandCenter.togglePlayPauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
NSLog(#"toggle button pressed");
return MPRemoteCommandHandlerStatusSuccess;
}];
or, if you prefer to use a method instead of a block:
[commandCenter.togglePlayPauseCommand addTarget:self action:#selector(toggleButtonAction)];
To stop:
[commandCenter.togglePlayPauseCommand removeTarget:self];
or:
[commandCenter.togglePlayPauseCommand removeTarget:self action:#selector(toggleButtonAction)];
You'll need to add this to the includes area of your file:
#import MediaPlayer;
For it to work in the background, you must have the background audio mode added to your app's capabilities.
Review this sample code from Apple for an example of usage. Likely your primary view controller is not actually becoming the first responder. An alternative usage is to place this code in your Application Delegate (which will always be the first responder) and respond to these events before they have had a chance to propagate, and potentially be consumed by other responders.
You have
respondsToSelector:#selector(beginReceivingRemoteControlEvents)]){
but in the method signature you have
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
The place where you are registering the signature is wrong. Just replace it by
respondsToSelector:#selector(beginReceivingRemoteControlEvents:)]){
You are missing the : which is making the app send the even to a non existing method I am assuming. I am surprised that your app is not crashing.
I am developing a iPhone application which sends tweets to twitter. For this I am using SA_OAuthTwitterEngine + MGTwitterEngine classes.
I register applicaiton to www.twitter.com/apps and pass Consumer key and Consumer secret to controller my code is this.
if(!_engine){
_engine = [[SA_OAuthTwitterEngine alloc] initOAuthWithDelegate:self];
_engine.consumerKey = slPcFUjUh5y1hex0zvEhPg;
_engine.consumerSecret = u6ydovMdP9yeiVqDukVhIzZPgJR9XDPUwfxymzNs;
}
UIViewController *controller = [SA_OAuthTwitterController controllerToEnterCredentialsWithTwitterEngine:_engine delegate:self];
if (controller){
[self presentModalViewController: controller animated: YES];
intTwitterFlag = 1;
}
Previously on twitter.com/apps I select Application type = client and my application will generate PIN and accessToken. But when i change my Application type = Browser it cannot generate PIN and accessToken.
Previously when application type is client i am giving user name and password and then control return to my application from the webview but now after entering user name and password it cannot dismissModalViewController but showing Select and Copy the PIN.
Thank you for your time and any help you can give me!
Here it is:just replace the method in SA_OAuthTwitterController.m:
- (void) webViewDidFinishLoad: (UIWebView *) webView {
_loading = NO;
//[self performInjection];
if (_firstLoad) {
[_webView performSelector: #selector(stringByEvaluatingJavaScriptFromString:) withObject: #"window.scrollBy(0,200)" afterDelay: 0];
_firstLoad = NO;
} else {
/*
NSString *authPin = [self locateAuthPinInWebView: webView];
NSLog(#"authPin: %#", authPin);
if (authPin.length) {
[self gotPin: authPin];
return;
}
NSString *formCount = [webView stringByEvaluatingJavaScriptFromString: #"document.forms.length"];
if ([formCount isEqualToString: #"0"]) {
[self showPinCopyPrompt];
}*/
//*****************************************************
// This is to bypass the pin requirement
// in case the call back URL is set in Twitter settings
//*****************************************************
[_engine requestAccessToken];
if ([_delegate respondsToSelector: #selector(OAuthTwitterController:authenticatedWithUsername:)])
{
[_delegate OAuthTwitterController: self authenticatedWithUsername: _engine.username];
}
[self performSelector: #selector(dismissModalViewControllerAnimated:) withObject: (id) kCFBooleanTrue afterDelay: 1.0];
//[self dismissModalViewControllerAnimated:YES];
}
[UIView beginAnimations: nil context: nil];
_blockerView.alpha = 0.0;
[UIView commitAnimations];
if ([_webView isLoading]) {
_webView.alpha = 0.0;
} else {
_webView.alpha = 1.0;
}
}
I too faced the same issue, and i just removed callback url from the twitter app settings. For my surprise login proceeds without any issue.
The replacement for this method
(void) webViewDidFinishLoad: (UIWebView *) webView
in the class SA_OAuthTwitterController.m works well.
Its better to use xAuth route for mobile apps
http://dev.twitter.com/pages/xauth
check XAuthTwitterEngine which implements xauth for the MGTwitterEngine