Accessing `shared` variable of `UIApplication` from inside `share extension` in Swift

我的梦境 提交于 2020-12-08 08:02:41

问题


I need to execute my host app from inside an extension. In Objective-C I've used this:

// Get "UIApplication" class name through ASCII Character codes.
NSString *className = [[NSString alloc] initWithData:[NSData dataWithBytes:(unsigned char []){0x55, 0x49, 0x41, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E} length:13] encoding:NSASCIIStringEncoding];
if (NSClassFromString(className))
{
    //  A different way to call [UIApplication sharedApplication]
    id object = [NSClassFromString(className) performSelector: @selector(sharedApplication)];
    //  These lines invoke selector with 3 arguements
    SEL selector = @selector(openURL:options:completionHandler:);
    id  (*method)(id, SEL, id, id, id) = (void *)[object methodForSelector: selector];
    method(object, selector, myURL, nil, nil);
    //  Close extension
    [self.extensionContext completeRequestReturningItems: @[] completionHandler: nil];
}

But in Swift I have a couple of issues:

1) UIApplication does not have sharedApplication method anymore. Instead it has a class property shared. So I can not perform a selector to get shared instance. I've tried to bypass this by writing an extension

extension UIApplication
{
    class func shared() -> UIApplication
    {
        return UIApplication.shared
    }
}

but I get an error Function produces expected type 'UIApplication'; did you mean to call it with '()'?. Adding these braces will give me an infinite loop.

2) Even if I get the instance somehow, I can't understand how to invoke open method.

let selector = NSSelectorFromString("open(_:options:completionHandler:)")
let method = object?.method(for: selector)
method(destinationURL, [String: Any](), nil)

The last line gives me Cannot call value of non-function type 'IMP'. When pressing on the type in apple's documents, nothing happens. I can't find a description of IMP and how to work with it.

You might say: "just set Require only app-extension-safe api to NO in your extension's settings and call UIApplication.shared normally". To which I would reply that my builds get rejected by iTunes Connect with a message Compliance with export requirements is required or something along those lines (iTunes Connect is in Russian when my entire OS is in English).

So here are the questions:

1) Is there a way to get UIApplication.shared using ASCII codes in Swift?

BTW I get class name like so

let codes = [CUnsignedChar](arrayLiteral: 0x55, 0x49, 0x41, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E)
let className = String(data: Data(bytes: UnsafeRawPointer(codes), count: 13), encoding: String.Encoding.ascii) ?? ""

2) How do I invoke a method that has type IMP?

Thank you very much.


回答1:


The problem is that you shouldn't try to access sharedApplication from your extension in the first place.

As per App Extension Programming Guide:

Some APIs Are Unavailable to App Extensions

Because of its focused role in the system, an app extension is ineligible to participate in certain activities. An app extension cannot:

  • Access a sharedApplication object, and so cannot use any of the methods on that object

So you may hack your way through it, but that will result in your application being rejected upon review.

However, to do what you're trying to do (open a URL) you don't need sharedApplication - you can simply do that using NSExtensionContexts open(_:completionHandler:)

extensionContext.open(myUrl, completionHandler: myCompletionHandler)



回答2:


Although .shared property is not available in extensions directly, you can access it via #keyPath:

let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as! UIApplication



来源:https://stackoverflow.com/questions/46240431/accessing-shared-variable-of-uiapplication-from-inside-share-extension-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!