I am having a problem using the new Facebook SDK invite system. The view controller which appears when using FBSDKAppInviteDialog displays very oddly, then disappears before the user has time to interact with it.
FBSDKAppInviteContent *content =[[FBSDKAppInviteContent alloc] init];
content.appLinkURL = [NSURL URLWithString:#"http://example.com"];
//content.appInvitePreviewImageURL = [NSURL URLWithString:#"https://www.example.com/my_invite_image.jpg"];
FBSDKAppInviteDialog *inviteDialog = [[FBSDKAppInviteDialog alloc] init];
if ([inviteDialog canShow]) {
inviteDialog.content = content;
inviteDialog.delegate = self;
[inviteDialog show];
}
This is what appears on the screen when the modal launches:
Does anyone know of any reason this would happen?
Edit[Sep 8, 2015 15:15 EDT]: We are currently getting an error code of 1; unknown error. Here is the exact print out:
Failed to perform app invite: The operation couldn’t be completed. (com.facebook.Facebook.platform error 1.)
Full Report => {
}
We thought it might be that we don't have friend permissions or something to do with iOS 9; however we are running our test on iOS 8, and we added friend permissions, and we have not seen a change.
I would call the validateWithError function they provided. It might give an idea of what the issue is.
FBSDKAppInviteDialog documentation
Related
I'm using the Multipeer Connectivity Framework to transfer files between devices. I'm using the standard MCAdvertiserAssistant and MCBrowserViewController to connect the devices. On the first try from device A to device B things work fine. Same things on the first transfer from device B to device A.
If you try either direction again, after MCBrowserViewController presents its dialog to choose a peer and you select one, the popup to accept the request on the other device never appears. No error messages, no calls to delegate methods - just nothing. Has anyone come across this and any ideas?
I had the same problem and solved it with initiating all the necessary components every time I start advertising or browsing for peers. It isn't the cleanest solution but in my case it works 100%.
The code below is how I implemented it, so this is without the build-in ViewController provided by Apple.
Please be aware that [session disconnect] is an async method which sometimes take a few seconds to complete.
- (void)startBrowsing
{
// Initiate new advertiser
isAdvertising = YES;
_peerID = [[MCPeerID alloc] initWithDisplayName:#"Wallet"];
_session = [[MCSession alloc] initWithPeer:_peerID];
_session.delegate = self;
_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:_peerID discoveryInfo:nil serviceType:#"made2pay"];
_advertiser.delegate = self;
// Start advertiser
[_advertiser startAdvertisingPeer];
}
- (void)stopBrowsing
{
[_advertiser stopAdvertisingPeer];
[_session disconnect];
_session = nil;
_peerID = nil;
_advertiser = nil;
isAdvertising = NO;
}
I've recently found out, that I do not receive any EKCalendar objects from EKEventStore in iOS7. In iOS 6.x.x there are no problems with same code snippet. When I'm trying to access defaultCalendarForNewEvents - I do receive a single EKCalendar object (as expected).
I do request access to entity type EKEntityTypeEvent.
The snippet:
__block NSMutableArray *calendarsArray = nil;
if ([self.eventsStore respondsToSelector:#selector(requestAccessToEntityType:completion:)]) {
[self.eventsStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
if (status == EKAuthorizationStatusAuthorized) {
calendarsArray = [[NSMutableArray alloc] initWithArray:[self.eventsStore calendarsForEntityType:EKEntityMaskEvent]];
}
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error!" message:#"You haven't granted access to calendars. Expected things are not going to happen." delegate:nil cancelButtonTitle:#"I understand" otherButtonTitles:nil];
[alert show];
}
}];
} else {
calendarsArray = [NSMutableArray arrayWithArray:[self.eventsStore calendarsForEntityType:EKEntityTypeEvent]];
}
I do receive 0 objects into calendarsArray. I've also tried to get it by "running through" all EKSources that are of type Local or CalDAV ([source calendarsForEntityType:] - got the same empty (0 object containing) set).
By the way - access to calendars IS granted.
Any suggestions?
After a brief investigation I have found out, that the problem was not in the code. It appears that the problem is in iOS 7.0.3 itself.
After deleting all the sync'ed calendars from the iDevice and adding it back all of the calendars were displayed both within the native Calendar application, and the one I made. After taking this action my code was able to retrieve the calendars from EventStore not depending on the method I would access calendars (via EKSources or EKEventStore itself).
I would like to detect when a user refused the microphone permission on my iOS application.
I only get this value when I try to record the microphone: -120.000000 db
But before to get this I have to set up an AVAudioSession. Is there another function?
And I got this message in the output:
Microphone input permission refused - will record only silence
Thanks.
If you are still compiling with iOS SDK 6.0 (as I am) you have to be a bit more indirect than #Luis E. Prado, as the requestRecordPermission method doesn't exist.
Here's how I did it. Remove the autorelease bit if you're using ARC. On iOS6 nothing happens, and on iOS7 either the 'microphone is enabled' message is logged or the alert is popped up.
AVAudioSession *session = [AVAudioSession sharedInstance];
if ([session respondsToSelector:#selector(requestRecordPermission:)]) {
[session performSelector:#selector(requestRecordPermission:) withObject:^(BOOL granted) {
if (granted) {
// Microphone enabled code
NSLog(#"Microphone is enabled..");
}
else {
// Microphone disabled code
NSLog(#"Microphone is disabled..");
// We're in a background thread here, so jump to main thread to do UI work.
dispatch_async(dispatch_get_main_queue(), ^{
[[[[UIAlertView alloc] initWithTitle:#"Microphone Access Denied"
message:#"This app requires access to your device's Microphone.\n\nPlease enable Microphone access for this app in Settings / Privacy / Microphone"
delegate:nil
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil] autorelease] show];
});
}
}];
}
EDIT: It turns out that the withObject block is executed in a background thread, so DO NOT do any UI work in there, or your app may hang. I've adjusted the code above. A client pointed this out on what was thankfully a beta release. Apologies for the mistake.
Please note that this will only work if built with Xcode 5, and not with 4.6
Add the AVFoundation Framework to your project
Then import the AVAudioSession header file, from the AVFoundation framework, where you intend to check if the microphone setting is enabled
#import <AVFoundation/AVAudioSession.h>
Then simply call this method
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
if (granted) {
// Microphone enabled code
}
else {
// Microphone disabled code
}
}];
The first time this method runs, it will show the prompt to allow microphone access and based on the users response it will execute the completion block. From the second time onwards it will just act based on the stored setting on the device.
Swift answer:
if AVAudioSession.sharedInstance().recordPermission() == .Denied {
print("Microphone permission refused");
}
Or you can use framework like PermissionScope which permit to easily check permissions. https://github.com/nickoneill/PermissionScope
Edit: Swift 3 answer:
import AVFoundation
...
if AVAudioSession.sharedInstance().recordPermission() == .denied {
print("Microphone permission refused");
}
I'm not 100% certain if we're allowed to talk about iOS 7 outside of Apple's devforums, but I found the answer you're looking for there.
In short, you'll find your solution in the AVAudioSession.h header file in the SDK. And if you want to make use of it while still supporting iOS 6, make certain to use "respondsToSelector:" to check for the API availability.
I have two (2) calendars (iCal) on my iPad (one personal, one for the app). They are sync'd to my iMac for testing only. (Saves me time making entries to the specific app calendar).
I am currently writing an app that needs to access the app's calendar. It is the primary calendar on the iPad. I am trying to get Apple's SimpleEKDemo (unmodified) to work with the app's calendar, but so far I can't even get it not crash, much less to return anything. I have been looking at Google and SO questions for hours now, and decided it's time to call in the big guns.
This is the code where it's crashing:
- (void)viewDidLoad
{
self.title = #"Events List";
// Initialize an event store object with the init method. Initilize the array for events.
self.eventStore = [[EKEventStore alloc] init];
self.eventsList = [[NSMutableArray alloc] initWithArray:0];
// Get the default calendar from store.
self.defaultCalendar = [self.eventStore defaultCalendarForNewEvents]; // <---- crashes here --------
// Create an Add button
UIBarButtonItem *addButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:
UIBarButtonSystemItemAdd target:self action:#selector(addEvent:)];
self.navigationItem.rightBarButtonItem = addButtonItem;
[addButtonItem release];
self.navigationController.delegate = self;
// Fetch today's event on selected calendar and put them into the eventsList array
[self.eventsList addObjectsFromArray:[self fetchEventsForToday]];
[self.tableView reloadData];
}
This is the output from the "crash":
2012-10-05 14:33:12.555 SimpleEKDemo[874:907] defaultCalendarForNewEvents failed: Error Domain=EKCADErrorDomain Code=1013 "The operation couldn’t be completed. (EKCADErrorDomain error 1013.)"
I need to make sure I'm on the correct calendar... how do I do that?
You need to ensure you ask permission before trying to access the Event Store. Note that you need to only call this once. If the user denies access, they need to go to iOS Settings (see comment in code) to enable permissions for your app.
/* iOS 6 requires the user grant your application access to the Event Stores */
if ([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)])
{
/* iOS Settings > Privacy > Calendars > MY APP > ENABLE | DISABLE */
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if ( granted )
{
NSLog(#"User has granted permission!");
}
else
{
NSLog(#"User has not granted permission!");
}
}];
}
In iOS 5, you are only allowed to access Events (EKEntityTypeEvent) in the Event Store, unlike in iOS 6, where you can access Reminders (EKEntityTypeReminder). But you need the above code to at least get granted 1 time.
I should also mention that you need to be granted permission BEFORE you access the EventStore, in your case: [self.eventStore defaultCalendarForNewEvents];.
Also, defaultCalendarForNewEvents would be the correct way to access the users Default Calendar. If you wish to access a calendar with another name, then you need to iterate through the calendars and choose the appropriate one based on the results returned.
//Check if iOS6 or later is installed on user's device *********
if([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)]) {
//Request the access to the Calendar
[eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted,NSError* error){
//Access not granted-------------
if(!granted){
NSString *message = #"Hey! I Can't access your Calendar... check your privacy settings to let me in!";
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Warning"
message:message
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil,nil];
//Show an alert message!
//UIKit needs every change to be done in the main queue
dispatch_async(dispatch_get_main_queue(), ^{[alertView show];});
//Access granted------------------
}
else
{
self.defaultCalendar=[self.eventStore defaultCalendarForNewEvents];
}
}];
}
//Device prior to iOS 6.0 *********************************************
else{
self.defaultCalendar=[self.eventStore defaultCalendarForNewEvents];
}
I've been using the classic Ben Gottlieb Twitter Open Source project to create a twitter login for iPad.
My code to instantiate the engine and display the login controller is:
if (!_engine) {
_engine = [[SA_OAuthTwitterEngine alloc] initOAuthWithDelegate:self];
[_engine setConsumerKey:#"kConsumerKey"];
[_engine setConsumerSecret:#"kConsumerSecret"];
}
if (![_engine isAuthorized]){
UIViewController *controller = [SA_OAuthTwitterController controllerToEnterCredentialsWithTwitterEngine:_engine delegate:self];
if (controller){
if ([controller respondsToSelector:#selector(setModalPresentationStyle:)] == YES) {
controller.modalPresentationStyle = UIModalPresentationFormSheet;
}
[self presentModalViewController:controller animated:YES];
return;
}
}
In addition, I set the URLS for SA_OAuthTwitterEngine to https:
self.requestTokenURL = [NSURL URLWithString: #"https://twitter.com/oauth/request_token"];
self.accessTokenURL = [NSURL URLWithString: #"https://twitter.com/oauth/access_token"];
self.authorizeURL = [NSURL URLWithString: #"https://twitter.com/oauth/authorize"];
and my TWITTER_DOMAIN in MGTwitterEngine.m has been changed to:
#define TWITTER_DOMAIN #"api.twitter.com/1"
Running this code in the simulator for both iPhone and iPad works like a charm. HOWEVER, whenever I test this code on an iPad device, I'm thrown this error:
Whoa there! The request token for this page is invalid. It may have
already been used, or expired because it is too old. Please go back to
the site or application that sent you here and try again; it was
probably just a mistake
(Screenshot attached).
Any suggestions on how to get the standard login screen to appear will be greatly appreciated
I had the same problem and tried Jeff's way. It didn't work either. For some unknown reason, check your time settings and set to automatically set the time. This worked for me.
I ran into the same issue. What happens is that the request doesn’t get a request token. You can explicitly call that:
SA_OAuthTwitterEngine *myEngine;
[myEngine requestRequestToken];
Hope this helps!