UIActivityViewController inside a Container View - ios

I use a UIActivityViewController inside a Container View. I want to share some text by using Email, twitter and facebook. While the last two works perfectly i have a problem with Email. The problem is that the composer view doesn't dismisses either by canceling the event nor by trying to send it! When the ActivityView appears i get the following message:
Launch Services: Registering unknown app identifier com.apple.mobilemail failed
Launch Services: Unable to find app identifier com.apple.mobilemail
This is strange since there is really no problem with the app identifier and i can share text with email, using ActivityViewController in other view controllers (when not in a container view).
My code, below:
- (void)openBtnTouched {
NSString *alertTitleString = [[[GlobalVariables sharedInstance].alertsArray objectAtIndex:self.selectedIndex]objectForKey:#"alertTitle"];
NSString *alertMsgString = [[[GlobalVariables sharedInstance].alertsArray objectAtIndex:self.selectedIndex]objectForKey:#"alertMessage"];
UIActivityViewController *activity;
activity = [[UIActivityViewController alloc] initWithActivityItems:#[alertTitleString,alertMsgString] applicationActivities:nil];
activity.excludedActivityTypes = #[
UIActivityTypeMessage,
UIActivityTypePostToWeibo,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAssignToContact,UIActivityTypeCopyToPasteboard];
activity.completionHandler = ^(NSString *activityType, BOOL completed){
NSLog(#"Activity Type selected: %#", activityType);
if (completed) {
NSLog(#"Selected activity was performed.");
} else {
if (activityType == NULL) {
NSLog(#"User dismissed the view controller without making a selection.");
} else {
NSLog(#"Activity was not performed.");
}
}
};
[self presentViewController:activity animated:YES completion:NULL];
}

I'm not sure whether your app is designed for iPhone, iPad, or both, but Apple are very specific about how to display a UIActivityViewController. From their documentation:
When presenting the view controller, you must do so using the appropriate means for the current device. On iPad, you must present the view controller in a popover. On iPhone and iPod touch, you must present it modally.
If you're displaying it in some other way (i.e, in a container view controller) you may well encounter this sort of weird behavior. I'd recommend you display the activity view controller as recommended by Apple.

Related

iOS Present an Ad Modal VC over main VC

I have an ad that presents as a modal over my main VC. The ad is timed - show once per app launch after the user has been using the app for 5 seconds. The following is in the main VC which has modal VC's being pushed.
-(void)viewDidLoad{
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"firstLaunch"] isEqualToNumber:[NSNumber numberWithInt:1]]) {
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"paidIAP"] isEqualToNumber:[NSNumber numberWithInt:0]] ) {
[self performSelector:#selector(showAdUnit) withObject:self afterDelay:5.0f];
}
}
}
-(void)showAdUnit{
NSLog(#"got to show ad unit");
[ADNetwork showAd:ADNetworkShowStyleInterstitial rootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
However, if the user goes to another section of the app prior to 5 seconds, the ad will not launch because of this warning
Warning: Attempt to present on whose view is not in the window hierarchy!
Basically, the ad will never show. How can I make the ad show exactly once per launch over the main screen even if the user clicks to push other screens? If this is not possible, how can I push the ad over any screen they happen to be on?
You should present it over your main window rootViewController like this :
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:adViewController animated:YES completion:nil];
This one will always have its view in the view hierarchy and you are guaranteed that your ad view controller will be presented above everything else.

How to dismiss and push new ViewController

In my application there is a floating button. Its function is to open available screens from anywhere.
Scenario
Suppose I have 4 screens and in each screen their is floating Button.
1. Home Screen
2. Services Screen
3. Contact Screen
4. Events
Now suppose I have opened all screens. And currently I am in Contact Screen and I want to go to Services.
Then I have to push services again thus creating the object of Services Screen. This creates a problem as if the user gooes 10 times to Services then 10 new objects will be created.
How can I implement this scenario ?
My Code:
if([sender tag]==1)
{
[push home];
}
else if([sender tag]==2)
{
[push services];
}
else if([sender tag]==3)
{
[push Contact];
}
else
{
[push events];
}
I prefer to use UITabBarController.
Try with this.
UIViewController *popViewController = //assign here Services Screen or what view you want to back
BOOL isExist = NO;
for (UIViewController *viewController in self.navigationController.viewControllers) {
if ([viewController isEqual:popViewController]) {
isExist = YES;//exist view controller. so you should not create a new one
[self.navigationController popViewControllerAnimated:YES];
}
}
if (isExist==NO) {//not exist view controller. so you should create a new one
[self.navigationController pushViewController:YourViewController animated:YES];
}
#NSUser, sorry for not answering your exact problem, but I would recommend using UIPageViewController for "hosting" and presenting your content view controllers one at a time. Here is a conceptual document from Apple with essential description and how-to's. Good luck.

How to know when a View Controller unwinds when it´s presented programmatically

I got this code that brings up the native "share" view where the user can post to facebook/twitter etc... There is a completion block, but this only get´s called when the VC shows itself, I need to know when it dismisses. Cause my app has different View Controllers for landscape / portrait mode, and I do not want to dismiss the view if the user rotates and the UIACtivityViewController is on screen.
I send a notification when the shared button is pressed to not dismiss the current view if user rotates the device. All i need now, is to know when it´s dismissed so I can reenable the function
- (IBAction)shareButtonPressed:(UIButton *)sender {
// Notify that another view is on screen to allow rotation without view disapearing.
[self sendNotificationWithName:#"landscapeViewHasPopupActive" andObject:#"empty string"];
NSString *message = #"Hello World!";
UIImage *imageToShare = [UIImage imageNamed:#"Icon.png"];
NSArray *postItems = #[message, imageToShare];
UIActivityViewController *activityVC = [[UIActivityViewController alloc]
initWithActivityItems:postItems
applicationActivities:nil];
[self presentViewController:activityVC animated:YES completion:^() {
}];
// Is showing landscape set to NO, and YES when this view disapears
}
In ios6 storyboards, there is a thing called an unwind segue. Add a method to the presenting controller to verify if unwind can/will happen. Check with google.
The same view controller that called the – presentViewController:animated:completion: method has it's counterpart: the – dismissViewControllerAnimated:completion: method.
When you want to dismiss the activityVC controller call the – dismissViewControllerAnimated:completion: method. Use the 'completion' block to execute the code you want when the view controller is dismissed.
Hope this helps!

Lack of a close button on UIActivityViewController

I am currently doing some updates for an iOS application. For the update I am going to take advantage of iOS6 capabilities. I am using a UIActivityViewController to get this done as well as some custom UIActivity activities. The main issue I am having is that there is no "Cancel" or "Close" button. The only way you can exit out of the activity view is if you either post something to a social network, or act like you are going to and then cancel.
NSArray* dataToShare = [[NSArray alloc] initWithObjects:#"blah", nil];
// Custom activities are allocated here
NSArray* customActivities = [[NSArray alloc] initWithObjects:activities, nil];
NSArray* excludedActivities = [[NSArray alloc] initWithObjects:exclusions, nil];
activityController = [[UIActivityViewController alloc] initWithActivityItems:formatArray applicationActivities:customActivities];
activityController.excludedActivityTypes = excludedActivities;
activityController.modalPresentationStyle = UIModalPresentationFormSheet;
[[UIApplication sharedApplication].keyWindow addSubview:self.view];
[[UIApplication sharedApplication].keyWindow bringSubviewToFront:activityController.view];
[self presentViewController:activityController animated:YES completion:^{ closureCode
}];
This does everything that I need inside of the activity controller in terms of networking content, I just don't have a close button. I don't know if it is the same issue but when the view disappears if I try to bring one up my "Share" menu again it tells me
<UIActivityViewController: 0x1e0db7d0> on <ShareDelegate: 0x1e048490> which is already presenting <UIActivityViewController: 0x21b1d4f0>
Thoughts? Thanks in advance!
*I am using:
iPad 2
Objective-C/C++
XCode 4.5
iOS6
From the docs for UIActivityViewController (emphasis is mine):
When presenting the view controller, you must do so using the appropriate means for the current device. On iPad, you must present the view controller in a popover. On iPhone and iPod touch, you must present it modally.
On the iPad, the popover will be cancelled by the user tapping outside of the popover.
On the iPhone/iPod touch, the modal view controller will be shown with a cancel button.
In short, don't use a form sheet on the iPad.

UIActivity activityViewController being presented modally on iPad instead of in popover

When using a customer UIActivity subclass in iOS 6, it's possible to specify a custom view controller that will be displayed when your action is chosen from the initial UIActionViewController's view. You do this by returning a reference to a custom view controller from your UIActivity subclass's activityViewController method.
According to the UIActivity class reference:
activityViewController
The default implementation of this method returns nil. Subclasses that provide additional UI using a view controller can override this method to return that view controller. If this method returns a valid object, the system presents the returned view controller for you, instead of calling the performActivity method. On iPad, your view controller is presented inside of a popover. On iPhone and iPod touch, your view controller is presented modally.
Your custom view controller should provide a view with your custom UI and should handle any user interactions inside those views. Upon completing the activity, do not dismiss the view controller yourself. Instead, call the activityDidFinish: method and let the system dismiss it for you.
Note that bit at the end of the first paragraph: On iPad, your view controller is presented inside of a popover. On iPhone and iPod touch, your view controller is presented modally.
However, on iPad the view controller returned by activityViewController always displays modally, no matter how I present the UIActivityViewController (either modally or via a popover). When presenting via a popover, it causes it to crash since it doesn't think it's been dismissed.
What am I doing wrong? Is this a bug in iOS 6?
Update: here's a simple Xcode project that illustrates the problem. Feel free to clone it and play around to see if you can see where we're going wrong: github.com/simonwhitaker/GSActivityDemo
As we are talking about the UIActivityViewController, which is the view showing the available activities to the user. Apple state the following...
Your app is responsible for configuring, presenting, and dismissing this view controller. Configuration for the view controller involves specifying the data objects on which the view controller should act. (You can also specify the list of custom services your app supports.) When presenting the view controller, you must do so using the appropriate means for the current device. On iPad, you must present the view controller in a popover. On iPhone and iPod touch, you must present it modally.
I took the last line as a sign that you have to handle how the view is presented, so I check whether the code is running on iPad and use a UIPopover accordingly. As you can sere here... https://github.com/bufferapp/buffer-uiactivity/blob/master/BufferUIActivity/Views/FirstViewController.m within the following method.
-(IBAction)openUIActivityView:(id)sender {
NSString *text = #"Hello world";
NSString *url = #"http://bufferapp.com";
NSArray *activityItems = #[text, url];
BufferUIActivity *bufferActivity = [[BufferUIActivity alloc] init];
UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:#[ bufferActivity ]];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:activityView animated:YES completion:^{
}];
} else {
// Change Rect to position Popover
self.popup = [[UIPopoverController alloc] initWithContentViewController:activityView];
[self.popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.width/2, 100, 100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
I think the issue with the activity view controller not showing in a popover is a bug and the docs reflect the correct intent. However, I don’t know of a way to workaround this atm.
The part about dismissing the view controller, however, is a different issue. You are not supposed to dismiss the view controller that you return from -[UIActivity activityViewController], but you are responsible for dismissing the popover that you have presented, which in turn will also remove your custom view controller from the hierarchy. (And because it works this way, I’m inclined to believe that the custom view controller would normally have to be shown in the popover.)
Here’s an example with code from your example app:
UIActivityViewController *vc = [[UIActivityViewController alloc] initWithActivityItems:activityItems
applicationActivities:applicationActivities];
vc.completionHandler = ^(NSString *activityType, BOOL completed){
[self.activityPopoverController dismissPopoverAnimated:YES];
};
I had the same problem in iOS 7. The solution to show the custom view in the popover is to create and show it in the -(void)performActivity method instead of returning it in -(UIViewController *)activityViewController.
You can see example code in my question/answer under this link:
iOS 7 custom UIActivity as popover
I just had the same problem but solved it by setting the ViewController to:
[yourViewController setModalPresentationStyle:UIModalPresentationPageSheet];
in
- (UIViewController *)activityViewController
hope this helps

Resources