When I press 'Cancel' on a TouchID prompt, the prompt disappears and the instantly reappears... My biometrics method is called inside ViewDidLoad, I added an NSLog inside ViewDidLoad and it is getting called when I dismiss the TouchID dialog. I've looked and tried several examples of how to implement TouchID, but all result in the same outcome.
- (void)useBiometrics{
LAContext* context = [[LAContext alloc] init];
NSError* error = nil;
NSString* result = #"Use Touch ID to login";
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:result reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
LoginViewController *loginController = [storyboard instantiateViewControllerWithIdentifier:#"ViewControllerROOTIdentifier"];
[self.navigationController pushViewController:loginController animated:NO];
FROM_LOGIN = YES;
NEEDS_LOGIN = FALSE;
});
}
else
{
switch (error.code) {
case LAErrorSystemCancel:
{
break;
}
case LAErrorUserCancel:
{
NSLog(#"TouchID canceled");
break;
}
case LAErrorAuthenticationFailed:
{
break;
}
case LAErrorPasscodeNotSet:
{
break;
}
case LAErrorBiometryNotAvailable:
{
break;
}
case LAErrorBiometryNotEnrolled:
{
break;
}
case LAErrorUserFallback:
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
break;
}
default:
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
break;
}
}
}
}];
}
else
{
switch (error.code) {
case LAErrorBiometryNotEnrolled:
{
break;
}
case LAErrorPasscodeNotSet:
{
NSLog(#"A passcode has not been set");
break;
}
default:
{
NSLog(#"TouchID not available");
break;
}
}
}
}
Related
I make sure that the call is inside the main thread. However, I still get a crash when the information is updated from the background thread.
Does anyone know how to fix this issue?
Code Block
- (void)viewDidLoad {
[super viewDidLoad];
[self styleConfiguration];
[self registerInAppPurchaseObservers];
__weak typeof (self) weakSelf = self;
[weakSelf.activityIndicator startAnimating];
dispatch_async(dispatch_get_main_queue(), ^{
[[GIFMIAPHelper defaultHelper] requestProductsWithCompletionHandler:^(BOOL success, SKProduct *productPro, NSError *error) {
__weak typeof (self) strongSelf = weakSelf;
[weakSelf.activityIndicator stopAnimating];
if (success) {
[strongSelf updateProductProProductInfo:productPro];
} else {
[strongSelf requestProductProFailed:error.localizedDescription];
}
}];
[FIRAnalytics logEventWithName:kFIREventScreenView parameters:#{
#"Screen name": #"Product Pro Purchase",
#"Screen class": NSStringFromClass(self.class),
}];
});
}
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.'
Here is what it calls
- (void)requestProductsWithCompletionHandler:(GIFMRequestProductsCompletionHandler)completionHandler {
#try {
self.completionHandler = [completionHandler copy];
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productsIdentifiers];
self.productsRequest.delegate = self;
[self.productsRequest start];
}
#catch (NSException *exception) {
DLog(#"Failed transaction %#", exception.description);
}
}
And the rest of the file:
#import "GIFMIAPHelper.h"
#import <SecureNSUserDefaults/NSUserDefaults+SecureAdditions.h>
#define SecureSalt #"SecuredPaymentSalt"
#interface GIFMIAPHelper()<SKProductsRequestDelegate, SKPaymentTransactionObserver>
#end
#implementation GIFMIAPHelper
+ (instancetype)defaultHelper {
static GIFMIAPHelper *defaultHelper;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSSet *productIdentifiers = [NSSet setWithObject:GIFMProduct_VomboPro];
defaultHelper = [[self alloc] initWithProductIdentifiers:productIdentifiers];
});
return defaultHelper;
}
- (instancetype)initWithProductIdentifiers:(NSSet *)productIdentifiers {
self = [super init];
if (self) {
NSString *udid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
[[NSUserDefaults standardUserDefaults] setSecret:[NSString stringWithFormat:#"%#%#", udid, SecureSalt]];
self.productsIdentifiers = productIdentifiers;
self.purchasedProductIdentifiers = [NSMutableSet set];
for (NSString *productId in productIdentifiers) {
BOOL productPurchased = [[NSUserDefaults standardUserDefaults] secretBoolForKey:productId];
if (productPurchased) {
[self.purchasedProductIdentifiers addObject:productId];
} else {
DLog(#"Not purchased: %#", productId);
}
}
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
return self;
}
- (void)requestProductsWithCompletionHandler:(GIFMRequestProductsCompletionHandler)completionHandler {
#try {
self.completionHandler = [completionHandler copy];
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productsIdentifiers];
self.productsRequest.delegate = self;
[self.productsRequest start];
}
#catch (NSException *exception) {
DLog(#"Failed transaction %#", exception.description);
}
}
- (void)buyVomoboPro:(SKProduct *)product {
#try {
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
#catch (NSException *exception) {
DLog(#"Failed transaction %#", exception.description);
}
}
- (BOOL)vomboProPurchased {
#ifdef DEBUG_PREMIUM_LEVEL
return YES;
#endif
#ifdef DEBUG_FREEMIUM_LEVEL
return NO;
#endif
return [self.purchasedProductIdentifiers containsObject:GIFMProduct_VomboPro];
}
- (void)restoreVomboProPurchase {
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void)storeProductPurchasedState:(NSString *)productIdentifier {
[self.purchasedProductIdentifiers addObject:productIdentifier];
[[NSUserDefaults standardUserDefaults] setSecretBool:YES forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)completeVomboProTransaction:(SKPaymentTransaction *)transaction {
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
NSString *productIdentifier = transaction.payment.productIdentifier;
[self storeProductPurchasedState:productIdentifier];
[[NSNotificationCenter defaultCenter] postNotificationName:GIFMIAPHelperProductPurchasedCompletedNotification object:productIdentifier];
}
- (void)vomboProTransactionFailed:(SKPaymentTransaction *)transaction {
#try {
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[[NSNotificationCenter defaultCenter] postNotificationName:GIFMIAPHelperProductPurchasedFailedNotification object:transaction.error.localizedDescription];
}
#catch (NSException *exception) {
DLog(#"Failed transaction %#", exception.description);
}
}
#pragma mark - SKProductsRequestDelegate, SKPaymentTransactionObserver
- (void)productsRequest:(nonnull SKProductsRequest *)request didReceiveResponse:(nonnull SKProductsResponse *)response {
NSLog(#"Fetched products");
self.productsRequest = NULL;
NSArray *products = response.products;
for (SKProduct *product in products) {
if ([product.productIdentifier isEqualToString:GIFMProduct_VomboPro]) {
NSLog(#"Found product: %# – Product: %# – Price: %0.2f", product.productIdentifier, product.localizedTitle, product.price.floatValue);
if (self.completionHandler){
self.completionHandler(YES, product, nil);
}
return;
}
}
NSError *error = [NSError errorWithDomain:#"SKProductsRequestNotFound" code:-1 userInfo:#{NSLocalizedDescriptionKey: #"Vombo Pro Not Found"}];
if (self.completionHandler){
self.completionHandler(NO, NULL, error);
}
return;
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
self.productsRequest = NULL;
if (self.completionHandler){
self.completionHandler(NO, NULL, error);
}
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
DLog(#"Restore Payment Finished");
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
DLog(#"Restore PaymentQueue Failed");
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
DLog(#"Payment Updated");
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
[self completeVomboProTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:NSLog(#"Failed");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self completeVomboProTransaction:transaction];
NSLog(#"Transaction state -> Restored");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
default:
break;
}
}
}
#end
Your code boils down to
- (void)viewDidLoad {
// main queue
[super viewDidLoad];
[weakSelf.activityIndicator startAnimating];
// still main queue
dispatch_async(dispatch_get_main_queue(), ^{
// main queue
[[GIFMIAPHelper defaultHelper] requestProductsWithCompletionHandler:^(BOOL success, SKProduct *productPro, NSError *error) {
// completion handler, not on a specific thread
[weakSelf.activityIndicator stopAnimating];
}];
});
}
Move dispatch_async(dispatch_get_main_queue() to the completion handler:
- (void)viewDidLoad {
// main queue
[super viewDidLoad];
[weakSelf.activityIndicator startAnimating];
// still main queue
[[GIFMIAPHelper defaultHelper] requestProductsWithCompletionHandler:^(BOOL success, SKProduct *productPro, NSError *error) {
// completion handler, not on a specific thread
dispatch_async(dispatch_get_main_queue(), ^{
// main queue
[weakSelf.activityIndicator stopAnimating];
});
}];
}
I am developing app like converting speech into text, here is my code,
I have used Apple's framework - speech.
- (void)viewDidLoad {
[super viewDidLoad];
[self.start_btn setEnabled:NO];
}
-(void)viewDidAppear:(BOOL)animated
{
self.speechRecognizer = [[SFSpeechRecognizer alloc]initWithLocale:[NSLocale localeWithLocaleIdentifier:#"en-US"]];
self.speechRecognizer.delegate = self;
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus authStatus) {
switch (authStatus) {
case SFSpeechRecognizerAuthorizationStatusAuthorized:
//User gave access to speech recognition
NSLog(#"Authorized");
[self.start_btn setEnabled:YES];
break;
case SFSpeechRecognizerAuthorizationStatusDenied:
//User denied access to speech recognition
NSLog(#"AuthorizationStatusDenied");
[self.start_btn setEnabled:NO];
break;
case SFSpeechRecognizerAuthorizationStatusRestricted:
//Speech recognition restricted on this device
NSLog(#"AuthorizationStatusRestricted");
[self.start_btn setEnabled:NO];
break;
case SFSpeechRecognizerAuthorizationStatusNotDetermined:
//Speech recognition not yet authorized
[self.start_btn setEnabled:NO];
break;
default:
NSLog(#"Default");
break;
}
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)start_record{
//CAncel the previous task if it's running
NSError * outError;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:&outError];
[audioSession setMode:AVAudioSessionModeMeasurement error:&outError];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&outError];
SFSpeechAudioBufferRecognitionRequest *request2 = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
self.audioEngine = [[AVAudioEngine alloc]init];
AVAudioInputNode *inputNode = self.audioEngine.inputNode;
if (request2 == nil) {
NSLog(#"Unable to created a SFSpeechAudioBufferRecognitionRequest object");
}
if (inputNode == nil) {
NSLog(#"Audio engine has no input node ");
}
//configure request so that results are returned before audio recording is finished
request2.shouldReportPartialResults = YES;
self.recognitionTask = [self.speechRecognizer recognitionTaskWithRequest:request2 resultHandler:^(SFSpeechRecognitionResult * result, NSError * error1) {
BOOL isFinal = false;
if(result != nil)
{
self.speech_txt.text = result.bestTranscription.formattedString;
// NSLog(#" the result:%#",result.bestTranscription.formattedString);
NSLog(#"%#",self.speech_txt.text);
isFinal = result.isFinal;
}
if (error1 != nil || isFinal) {
[self.audioEngine stop];
[inputNode removeTapOnBus:0];
// [self.audioEngine stop];
// [self.recognitionRequest endAudio];
self.recognitionRequest = nil;
self.recognitionTask = nil;
[self.start_btn setEnabled:YES];
[self.start_btn setTitle:#"Start Recording" forState:UIControlStateNormal];
}
}];
AVAudioFormat *recordingFormat = [inputNode outputFormatForBus:0];
[inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when){
[self.recognitionRequest appendAudioPCMBuffer:buffer];
}];
NSError *error1;
[self.audioEngine prepare];
[self.audioEngine startAndReturnError:&error1];
self.speech_txt.text = #"(Go ahead , I'm listening)";
}
//MARK: SFSpeechRecognizerDelegate
-(void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available
{
if (available) {
[self.start_btn setEnabled:YES];
[self.start_btn setTitle:#"Start Recording" forState:UIControlStateNormal];
}
else{
[self.start_btn setEnabled:NO];
[self.start_btn setTitle:#"Recognition not available" forState:UIControlStateDisabled];
}}
- (IBAction)start_btn_action:(id)sender {
if (self.audioEngine.isRunning) {
[self.audioEngine stop];
[self.recognitionRequest endAudio];
[self.start_btn setEnabled:NO];
[self.start_btn setTitle:#"Stopping" forState:UIControlStateDisabled];
}
else{
[self start_record];
[self.start_btn setTitle:#"Stop Recording" forState:#""];
}}
I have implemented this code, while running it shows error like:
[Utility] +[AFAggregator logDictationFailedWithError:] Error Domain=kAFAssistantErrorDomain Code=203 "Timeout" UserInfo={NSLocalizedDescription=Timeout, NSUnderlyingError=0x170250140 {Error Domain=SiriSpeechErrorDomain Code=100 "(null)"}}
How can I resolve this?
I am making a game in which the player can achieve a positive high score or a negative low score depending on the choices they make. The high score has been working fine, but I'm having trouble with the low score.
-(void)authenticateLocalPlayer{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES;
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
else{
_leaderboardIdentifier = leaderboardIdentifier;
}
}];
}
else{
_gameCenterEnabled = NO;
}
}
};
}
-(void)reportScore{
GKScore *highscore = [[GKScore alloc] initWithLeaderboardIdentifier:_leaderboardIdentifier];
highscore.value = HighScoreNumber;
[GKScore reportScores:#[highscore] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
-(void)showLeaderboardAndAchievements:(BOOL)shouldShowLeaderboard{
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init];
gcViewController.gameCenterDelegate = self;
if (shouldShowLeaderboard) {
gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
gcViewController.leaderboardIdentifier = _leaderboardIdentifier;
}
else{
gcViewController.viewState = GKGameCenterViewControllerStateAchievements;
}
[self presentViewController:gcViewController animated:YES completion:nil];
}
You'll notice leaderboardidentifier, it is useful for reporting scores to the default leaderboard, but when I try to get it to work for two different ones, the code shuts down.
I've tried adding this to "Report Score":
GKScore *lowscore = [[GKScore alloc] initWithLeaderboardIdentifier:_leaderboardIdentifier];
lowscore.value = LowScoreNumber;
[GKScore reportScores:#[lowscore] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
}
Then, I change the leaderboard identifiers to match itunesconnect, but I'm not sure how I need to change authenticateLocalPlayer and shouldShowLeaderboardandAchievements.
I have some experience with game center. I have two games on the App Store that have multiple leaderboards (Squared!! and Primes!).
Instead of having one method for each leaderboard I made one method for submitting scores. Here is that method:
-(void) submitScore:(int64_t)score Leaderboard: (NSString*)leaderboard
{
//1: Check if Game Center
// features are enabled
if (!_gameCenterFeaturesEnabled) {
return;
}
//2: Create a GKScore object
GKScore* gkScore =
[[GKScore alloc]
initWithLeaderboardIdentifier:leaderboard];
//3: Set the score value
gkScore.value = score;
//4: Send the score to Game Center
[gkScore reportScoreWithCompletionHandler:
^(NSError* error) {
[self setLastError:error];
BOOL success = (error == nil);
if ([_delegate
respondsToSelector:
#selector(onScoresSubmitted:)]) {
[_delegate onScoresSubmitted:success];
}
}];
}
When you want to submit your high scores all you have to do is add something like:
[[GCHelper sharedGameKitHelper] submitScore:myLowScore Leaderboard:TELS];
[[GCHelper sharedGameKitHelper] submitScore:myHighScore Leaderboard:TEHS];
GCHelper is the class that contains my submitScore:Leaderboard: method.
To view your leaderboards or achievements within your app try this:
- (void) presentLeaderboards {
GKGameCenterViewController* gameCenterController = [[GKGameCenterViewController alloc] init];
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
gameCenterController.gameCenterDelegate = self;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
- (void) gameCenterViewControllerDidFinish:(GKGameCenterViewController*) gameCenterViewController {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void) presentAchievements {
GKGameCenterViewController* gameCenterController = [[GKGameCenterViewController alloc] init];
gameCenterController.viewState = GKGameCenterViewControllerStateAchievements;
gameCenterController.gameCenterDelegate = self;
I hope this answers your question!
I have problem with the attached codе. It have to close the currently displayed modalViewController when the user tap once on the cancel button instead of twice as it do now.
Code
- (BOOL)isIOS6 {
BOOL native = YES;
if([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0f){
native = NO;
}
return native;
}
- (void)twitterShare {
DLog(#"is ios6: %d", [self isIOS6]);
if ([self isIOS6]) {
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
{
NSString *textToShare = #"Test";
SLComposeViewController *twitterComposeViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
twitterComposeViewController.completionHandler = ^(SLComposeViewControllerResult result){
DLog(#"result: %d", result);
if (result == 1) {
Dlog(#"Shared");
[[NSNotificationCenter defaultCenter] postNotificationName:#"notitificationName" object:nil];
DLog(#"Sended provide bonus notification");
[self disableButtonWithTag:GrowthButtonTwitterConnectTag];
DLog(#"disable that button.");
} else {
Dlog(#"canceled...");
}
};
[twitterComposeViewController setInitialText:textToShare];
[self presentViewController:twitterComposeViewController animated:YES completion:nil];
} else {
DLog(#"Twitter not available");
}
} else {
// iOS 5 not supported message
[[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"ATTENTION", nil)
message:NSLocalizedString(#"IOS6_OR_ABOVE_FEATURE", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles:nil, nil] autorelease] show];
}
}
I've manage to fix that issue with the following code:
tweetSheet.completionHandler = ^(SLComposeViewControllerResult result) {
switch(result) {
// This means the user cancelled without sending the Tweet
case SLComposeViewControllerResultCancelled:
break;
// This means the user hit 'Send'
case SLComposeViewControllerResultDone:
[[NSNotificationCenter defaultCenter] postNotificationName:#"kGrowthProvideTwitterBonus" object:nil];
DLog(#"Sended provide bonus notification");
[self disableButtonWithTag:TTGrowthButtonTwitterConnectTag];
break;
}
// dismiss the Tweet Sheet
dispatch_async(dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:NO completion:^{
NSLog(#"Tweet Sheet has been dismissed.");
}];
});
};
I am wondering if it's possible to post something on a user's facebook wall using SLComposeViewController but without showing the share sheet/dialog?
Following is the code I am using:
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
SLComposeViewControllerCompletionHandler myBlock = ^(SLComposeViewControllerResult result){
if (result == SLComposeViewControllerResultCancelled) {
NSLog(#"Cancelled");
} else
{
NSLog(#"Done");
}
[controller dismissViewControllerAnimated:YES completion:Nil];
};
controller.completionHandler =myBlock;
[controller setInitialText:eventInfoToFacebook];
[self presentViewController:controller animated:YES completion:Nil];
}
Thanks in advance.
Import the Social Framework:
#import <Social/Social.h>
-
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
SLComposeViewControllerCompletionHandler myBlock = ^(SLComposeViewControllerResult result){
if (result == SLComposeViewControllerResultCancelled) {
NSLog(#"Cancelled");
} else
{
NSLog(#"Done");
}
[controller dismissViewControllerAnimated:YES completion:Nil];
};
controller.completionHandler =myBlock;
[controller setInitialText:#"Test Post from mobile.safilsunny.com"];
[controller addURL:[NSURL URLWithString:#"http://www.mobile.safilsunny.com"]];
[controller addImage:[UIImage imageNamed:#"fb.png"]];
[self presentViewController:controller animated:YES completion:Nil];
}
else{
NSLog(#"UnAvailable");
}
}
/
//Deprecated in iOS6
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
ACAccount *account = [[ACAccount alloc] initWithAccountType:accountType];
NSLog(#"%#, %#", account.username, account.description);
}];
Here I got the answer, for posting image data and url together we need to add Social.framework, this framework is available in iOS6.
Just add the Social.framework in your project and add the blew code.
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook])
{
SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
SLComposeViewControllerCompletionHandler myBlock = ^(SLComposeViewControllerResult result){
if (result == SLComposeViewControllerResultCancelled) {
NSLog(#"ResultCancelled");
} else
{
NSLog(#"Success");
}
[controller dismissViewControllerAnimated:YES completion:Nil];
};
controller.completionHandler =myBlock;
[controller addURL:[NSURL URLWithString:#"https://itunes.apple.com/us/app/social-checkin/id504791401?mt=8"]];
if (encoded_ImageData == nil) {
[controller addImage:[UIImage imageNamed:#"No_ImageFound.png"]];
}
else
{
[controller addImage:[UIImage imageWithData:encoded_ImageData]];
}
NSString *businessName;
//Set business name string to be passed on facebook
if (m_BusinessNameString == nil || [m_BusinessNameString isEqualToString:#""])
{
businessName = #"Business name not specified!";
}
else
{
businessName = [m_BusinessNameString uppercaseString];
}
NSString *nameString = [NSString stringWithFormat:#"CHECKED IN #"];
//user has checked in with his friends if sc-merchant
NSString *friendsString;
if ([checkedFriendsNameArray count] > 0)
{
NSMutableString *checkedFriendsTempStr = [[NSMutableString alloc] init];
for (NSMutableString *checkedStr in checkedFriendsNameArray)
{
[checkedFriendsTempStr appendFormat:[NSString stringWithFormat:#"%#,",checkedStr]];
friendsString = [NSString stringWithFormat:#"WITH %#",checkedFriendsTempStr];
}
}
else
{
friendsString = [NSString stringWithFormat:#"WITH NO FRIENDS"];
}
NSString *fname= [[NSUserDefaults standardUserDefaults] valueForKey:#"userfname"];
NSString *lname= [[NSUserDefaults standardUserDefaults] valueForKey:#"userlname"];
NSString *name=[fname stringByAppendingString:[NSString stringWithFormat:#"%#",lname]];
NSString *main_TextString =[NSString stringWithFormat:#"%# \n %# %# %# %#",upperCaseStatusString,name,nameString,businessName,friendsString];
[controller setInitialText:main_TextString];
[self presentViewController:controller animated:YES completion:Nil];
}
else{
NSLog(#"UnAvailable");
}
Add below Code in your ViewController and import below framework.
import FBSDKCoreKit
import FBSDKLoginKit
import FBSDKShareKit
#IBAction func btnPostClick(_ sender: Any)
{
if (FBSDKAccessToken.current() != nil)
{
if FBSDKAccessToken.current().hasGranted("publish_actions"){
postOnFB()
}
else
{
let loginManager = FBSDKLoginManager()
loginManager.logIn(withPublishPermissions: ["publish_actions"], from: self, handler: { (result, error) in
if error == nil{
self.postOnFB()
}
else{
print(error?.localizedDescription ?? "")
}
})
}
}
else
{
let loginManager = FBSDKLoginManager()
loginManager.logIn(withPublishPermissions: ["publish_actions"], from: self, handler: { (result, error) in
if error == nil{
self.postOnFB()
}
})
}
}
func postOnFB()
{
FBSDKGraphRequest(graphPath: "me/feed", parameters: ["message": "YOUR MESSAGE"], httpMethod: "POST").start { (connection, result, error) in
if error == nil{
print("post id \(result ?? "")")
}
else{
print("error is \(error?.localizedDescription ?? "")")
}
}
}
this is possible in facebook-ios-sdk 3.0.
here
i am making the share with this code.
[FBRequestConnection startWithGraphPath:#"me/feed"
parameters:params
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection,
NSDictionary * result,
NSError *error) {
if (error) {
NSLog(#"Error: %#", [error localizedDescription]);
} else {
}
}];
i called this method when user clicks share button and there is no dialog with the user it directly post to the users wall. params is parameters that sharing includes.