30

TLDR:是否可以在 iOS 应用程序和它的扩展程序之间发送实时消息或通知?

我正在编写一个带有扩展的 iOS 应用程序,这些应用程序是相同的一部分App Group并共享相同的 CoreData(SQLite 数据库)。我可以使用应用程序和扩展程序中的 CoreData 读取和写入数据库,它们都共享相同的内容。

我的问题是:是否可以在应用程序和扩展程序之间发送消息或通知以通知对方在必要时进行更新?

我尝试通过发送通知,NSNotificationCenter但这不会“退出”应用程序/扩展程序,如果我尝试写信给共享组NSUserDefaults并收听NSUserDefaultsDidChangeNotification. 这在应用程序内部有效,但扩展程序没有收到任何内容(当我知道它已启动并且共享相同时NSUserDefaults)。知道如何保持同步吗?

4

4 回答 4

33

TLDR:不,但有一个 hack

无论有没有扩展,iOS 应用程序都没有真正的进程间通信。NSDistributedNotification仍然没有从 OS X 到 iOS,而且可能不会。

使用某些扩展类型,您可以通过打开 URLNSExtensionContext并使用它们将数据传递给处理 URL 的应用程序。这会将应用程序带到前台,这听起来不像您想要的。

不过,有一个 hack 可能会为您提供所需的东西。

  • 不要写入用户默认值,而是写入应用组目录中的文件。
  • 不要只是直接写入文件 - 用于对文件NSFileCoordinator进行协调写入。
  • 在想要了解文件更改的对象上实现NSFilePresenter,并确保调用[NSFileCoordinator addFilePresenter:someObject]
  • presentedItemDidChange在文件演示器上实现可选方法。

如果您做对了所有这些,您可以从应用程序或扩展程序写入此文件,然后presentedItemDidChange在另一个文件中自动调用。作为奖励,您当然可以读取该文件的内容,因此您可以来回传递任意数据。

于 2014-11-19T18:48:25.967 回答
10

有一个 hack 可用于在 iOS 中的任何两个应用程序或应用程序和扩展程序之间进行通信。唯一的 - 它不适用于 NetworkExtension,因为 Apple 阻止了其中的任何 I/O。

您可以通过以下方式向 DarwinNotificationCenter 发布通知:

    let notificationName = CFNotificationName("com.notification.name" as CFString)
    let notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()

    CFNotificationCenterPostNotification(notificationCenter, notificationName, nil, nil, false)

在您的应用中添加观察者:

    let notificationName = "com.notification.name" as CFString
    let notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()

    CFNotificationCenterAddObserver(notificationCenter,
                                    nil,
                                    { (
                                        center: CFNotificationCenter?,
                                        observer: UnsafeMutableRawPointer?,
                                        name: CFNotificationName?,
                                        object: UnsafeRawPointer?,
                                        userInfo: CFDictionary?
                                        ) in

                                        print("Notification name: \(name)")
                                    },
                                    notificationName,
                                    nil,
                                    CFNotificationSuspensionBehavior.deliverImmediately)

一些链接: https ://github.com/choefele/CCHDarwinNotificationCenter

https://developer.apple.com/documentation/corefoundation/1542572-cfnotificationcentergetdarwinnot

https://developer.apple.com/library/content/documentation/Darwin/Conceptual/MacOSXNotifcationOv/DarwinNotificationConcepts/DarwinNotificationConcepts.html

于 2018-02-01T09:02:28.667 回答
8

对于在主机应用程序和应用程序扩展之间进行通用双向通信的另一种方法,请尝试MMWormhole

http://www.mutualmobile.com/posts/mmwormhole https://github.com/mutualmobile/MMWormhole

它是 CFNotificationCenter 的一个相当轻量级的包装器,并使用“Darwin”通知来进行进程间通信(IPC)。

它使用应用程序的共享容器来回传递有效负载,并封装甚至必须自己创建文件。

该类(以及 repo 中的示例应用程序)似乎运行良好,并且响应迅速。

我希望这也有帮助。

于 2015-05-11T06:00:10.657 回答
2

我一直在努力解决同样的问题,也没有找到一个干净的解决方案。解决此问题的另一种方法是简单地在扩展程序中运行一个计时器并定期检查共享容器首选项/数据库中的值,然后在需要时进行更新。不优雅,但它似乎工作。

于 2015-01-23T16:27:44.403 回答