5

I am trying to port over our app to Mac. But it seems that what works for iOS/iPadOS does not show up on Mac app. Nothing popups at all.

let activityController = UIActivityViewController(activityItems:items, applicationActivities:nil)

activityController.setValue(NSLocalizedString("App Name", comment:""), forKey:"subject")
activityController.modalPresentationStyle = .popover

let popoverController = activityController.popoverPresentationController

if popoverController != nil {
      popoverController!.barButtonItem = sender
      popoverController!.permittedArrowDirections = .down
}

self.present(activityController, animated:true, completion:nil)

Saw an error message that might be related:

setting preferences outside an application's container requires user-preference-write or file-write-data sandbox access

I have tried various settings in sandbox with no good result.

PS: Got it working after removing this line: activityController.setValue(NSLocalizedString("App Name", comment:""), forKey:"subject")

What option is shown also dependent. For example, if have a string and an image in items, then Save to Photos will not be shown.

Lim Thye Chean
  • 8,704
  • 9
  • 49
  • 88
  • `UIActivityViewController` displays for me on a Mac. Try removing the restriction on permitted arrow directions. – rmaddy Oct 08 '19 at 16:18
  • Hi, thanks for helping. This does not work, but I saw a message " Contents Need Refresh: Yes): setting preferences outside an application's container requires user-preference-write or file-write-data sandbox access" - I have set the Pictures folder to read/write, is there anything else I need to set in Sandbox? – Lim Thye Chean Oct 08 '19 at 22:50
  • 1
    @rmaddy can you please show your code? When I show UIActivityViewController I only get one "button" with "More" text. – sabiland Oct 10 '19 at 09:06
  • @sabiland You actually got a window show up? Mine nothing shows. Have you set up anything in Xcode for something to show up? – Lim Thye Chean Oct 10 '19 at 13:51
  • 1
    I get only mini-small popup with single button “more” which opens system settings :S :) – sabiland Oct 10 '19 at 14:50
  • I also tried to add sandbox read/write settings but without success. – sabiland Oct 10 '19 at 14:53
  • @LimThyeChean Make sure your app doesn't lose focus, such as having a breakpoint in Xcode. The activity view automatically disappears as soon as your app loses focus. – rmaddy Oct 10 '19 at 15:56
  • @rmaddy I just tap on the button that suppose to pop up the activity view... and the button dim, nothing happened. I tried with/without the popover... still does not work. I have made sure that File Access for Downloads/Pictures folders are read/write. – Lim Thye Chean Oct 10 '19 at 23:01
  • 1
    I've also tried everything, no success. – sabiland Oct 11 '19 at 07:09
  • Same here. Does not work :( – Sunkas Oct 18 '19 at 09:23
  • 1
    I got it to work - after I removed this line: activityController.setValue(NSLocalizedString("App Name", comment:""), forKey:"subject") – Lim Thye Chean Oct 18 '19 at 16:01

3 Answers3

1

Hmm, I seem to have an interesting similar problem. I also get a "More" mini-popup. But if I use a UIButton instead of a UIView as a target it works.

Calling this code from with UIButton works:

func shareImage(_ image: UIImage, from fromView: UIView) {
    let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
    activityViewController.popoverPresentationController?.sourceView = fromView
    activityViewController.popoverPresentationController?.sourceRect = fromView.bounds
    self.present(activityViewController, animated: true, completion: nil)
}

Could be a bug in macOS/Catalyst?

It also seems to be dependent on what type of item is shared. Same code with PDF-data wont share on macOS. But a UIImage is working just fine :/

Sunkas
  • 9,542
  • 6
  • 62
  • 102
  • I got it to work after removing this line: activityController.setValue(NSLocalizedString("App Name", comment:""), forKey:"subject") – Lim Thye Chean Oct 18 '19 at 16:02
  • I also checked the image can be sent to Photos app, send via email... but not AirDrop. – Lim Thye Chean Oct 18 '19 at 16:11
  • I copy/pasted your code (with my UIButton), but I still get "More" popup :) Jesus:) – sabiland Oct 21 '19 at 11:42
  • 3
    I have found the issue I got. I was sending PNG to UIActivityViewController. This was the problem. When I sent plain UIImage, everything was ok :) – sabiland Oct 23 '19 at 06:14
  • When I chose Add to photos, I get this exception: [xpc.exceptions] connection to service on pid 17561 named com.apple.share.System.add-to-iphoto.apple-extension-service: Exception caught during decoding of received selector _completeRequestReturningItems:forExtensionContextWithUUID:completion:, dropping incoming message. Exception: Exception while decoding argument 0 (#2 of invocation): Exception: value for key 'NS.objects' was of unexpected class 'NSURL'. Allowed classes are '{( NSDate, NSNumber, NSData, NSDictionary, NSArray, NSString )}'. – sabiland Oct 23 '19 at 07:18
0
    let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

    let document = documentURL.appendingPathComponent("myFile.mp3")

    let activityController = UIActivityViewController(activityItems: [document], applicationActivities: nil)

    DispatchQueue.main.async {
                    
        activityController.modalPresentationStyle = .popover
        
        let popoverController = activityController.popoverPresentationController
        
        if popoverController != nil {
            
            popoverController!.sourceView = self.myUIButton
            popoverController!.sourceRect = self.myUIButton.bounds
            popoverController!.permittedArrowDirections = .any

        }
        
        self.present(activityController, animated: true) {
            
            print("UIActivityViewController was presented")
            
        }
        
    }
Michael N
  • 436
  • 5
  • 6
-2
#if _MAC_CATALYST_
//fix mac catalyst bug: UIActivityViewController add image to photo
@interface NSObject (FixCatalystBug)

@end

@implementation NSObject  (FixCatalystBug)

+ (void)load{
    Class cls = NSClassFromString(@"NSXPCDecoder");
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        SEL selectors[] = {
            #pragma clang diagnostic push
            #pragma clang diagnostic ignored "-Wundeclared-selector"
            @selector(_validateAllowedClass:forKey:allowingInvocations:)
            #pragma clang diagnostic pop
        };

        for (NSUInteger index = 0; index < sizeof(selectors) / sizeof(SEL); ++index) {
            SEL originalSel = selectors[index];
            SEL swizzledSel = NSSelectorFromString([@"fs_swizzled_" stringByAppendingString:NSStringFromSelector(originalSel)]);
            [cls fs_exchangeImpWithOriginalSel:originalSel swizzledSel:swizzledSel];
        }
    });
}

- (BOOL)fs_swizzled__validateAllowedClass:(Class)cls forKey:(id)key allowingInvocations:(id)allowingInvocations{
    BOOL _validate = NO;
    @try {
        _validate = [self fs_swizzled__validateAllowedClass:cls forKey:key allowingInvocations:allowingInvocations];
    } @catch (NSException *exception) {
        if ([key isEqualToString:@"NS.objects"] && [cls isKindOfClass:[NSURL class]]) {
            _validate = YES;
        }
    }
    return _validate;
}

@end
#endif
  • 2
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – dirtydanee Apr 17 '20 at 08:41