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

5 xcode uiapplication ios swift

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];
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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) ?? ""
Run Code Online (Sandbox Code Playgroud)

2)如何调用具有类型的方法IMP

非常感谢你。

mag*_*zbc 6

问题是您不应该sharedApplication首先尝试从您的扩展程序进行访问。

根据应用程序扩展编程指南

某些 API 对应用扩展不可用

由于其在系统中的重点作用,应用程序扩展没有资格参与某些活动。应用扩展不能:

  • 访问sharedApplication对象,因此无法使用该对象上的任何方法

因此,您可能会破解它,但这将导致您的申请在审核时被拒绝。

然而,要做你想做的事情(打开一个 URL),你不需要sharedApplication- 你可以简单地使用NSExtensionContexts open(_:completionHandler:)来做到这一点

extensionContext.open(myUrl, completionHandler: myCompletionHandler)
Run Code Online (Sandbox Code Playgroud)

  • 问题是“extensionContext”无法打开主机应用程序。 (4认同)

Ale*_*hov 5

尽管.shared属性不能直接在扩展中使用,但您可以通过以下方式访问它#keyPath

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

  • 我认为 keyPath 就像访问私有 API,因此 Apple 会在发布过程中拒绝您的应用程序。 (2认同)