【问题标题】:Accessing `shared` variable of `UIApplication` from inside `share extension` in Swift从 Swift 中的“共享扩展”内部访问“UIApplication”的“共享”变量
【发布时间】:2017-09-15 13:11:30
【问题描述】:

我需要从扩展程序中执行我的主机应用程序。在Objective-C 我用过这个:

// 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];
}

但在Swift 我有几个问题:

1) UIApplication 不再有 sharedApplication 方法。相反,它有一个类属性shared。所以我不能执行选择器来获取共享实例。我试图通过编写扩展来绕过这个

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

但我收到错误 Function produces expected type 'UIApplication'; did you mean to call it with '()'?。添加这些大括号会给我一个无限循环。

2)即使我以某种方式获得了实例,我也无法理解如何调用open 方法。

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

最后一行给了我Cannot call value of non-function type 'IMP'。当按下苹果文档中的类型时,没有任何反应。我找不到IMP 的描述以及如何使用它。

您可能会说:“只需在您的分机设置中将Require only app-extension-safe api 设置为NO 并正常调用UIApplication.shared”。我会回复说我的构建被iTunes Connect 拒绝,并带有一条消息Compliance with export requirements is required 或类似的内容(当我的整个操作系统都是英文时,iTunes Connect 是俄文的)。

以下是问题:

1) 有没有办法使用Swift 中的ASCII 码获取UIApplication.shared

顺便说一句,我得到这样的类名

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) 如何调用类型为 IMP 的方法?

非常感谢。

【问题讨论】:

  • 你的扩展对我有用...检查你的 Swift 版本
  • @paper1111 如果您在谈论Objective-C 代码:它正在工作。我在 Swift 中复制相同的行为时遇到问题。
  • “出口合规”是关于确认您的应用符合出口法律(例如软件加密)。我想知道这与您在此处所述的问题有何关系。
  • @Igor 我说的是 Swift
  • @all,我在我的应用程序中实现了共享扩展,在 iOS 13 中,由于 UIApplication.shared 现在不可用,我的共享扩展应用程序无法打开主应用程序来接收共享文件/图像。以前的所有版本都可以正常工作。那么,开发人员如何从不同来源接收/导入数据呢?任何解决方法?

标签: ios swift xcode uiapplication


【解决方案1】:

问题是你不应该首先尝试从你的扩展程序访问sharedApplication

根据App Extension Programming Guide

某些 API 不适用于应用扩展

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

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

因此,您可以自行破解,但这会导致您的申请在审核时被拒绝。

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

extensionContext.open(myUrl, completionHandler: myCompletionHandler)

【讨论】:

  • 问题是extensionContext无法打开宿主应用。
【解决方案2】:

虽然.shared属性不能直接在扩展中使用,你可以通过#keyPath访问它:

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

【讨论】:

  • 我认为keyPath就像访问一个私有API,所以Apple会在发布过程中拒绝你的应用程序。
  • @AlessioCrestani,不,keyPaths 不像使用私有 API。
猜你喜欢
  • 2011-11-01
  • 1970-01-01
  • 2018-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多