如何在iOS App包含扩展和扩展(不是主机应用程序)之间进行通信

Lud*_*dry 23 core-data nsnotificationcenter ios swift ios-extensions

TLDR:是否可以在iOS App和它的Extension之间发送实时消息或通知?

我正在编写一个iOS应用程序,其扩展名是相同的,App Group并共享相同的CoreData(SQLite数据库).我可以使用App中的CoreData读取和写入数据库,并且从扩展程序中,它们共享相同的内容.

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

我尝试发送通知,NSNotificationCenter但不会"退出"应用程序/扩展,如果我尝试写入共享的组NSUserDefaults并听取相同的问题NSUserDefaultsDidChangeNotification.这适用于应用程序,但扩展程序没有收到任何东西(当我知道它已启动并且它共享相同NSUserDefaults).知道如何让事情保持同步吗?

Tom*_*ton 26

TLDR:不,但有一个黑客

iOS应用程序没有真正的进程间通信,有或没有扩展.NSDistributedNotification仍然没有从OS X到iOS,也可能不会.

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

但是,有一个hack可能会让你得到你需要的东西.

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

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


maf*_*nya 9

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

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

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

    CFNotificationCenterPostNotification(notificationCenter, notificationName, nil, nil, false)
Run Code Online (Sandbox Code Playgroud)

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

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

部分链接: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

  • 好吧,只是一个警告 - 你无法在回调中访问“self”。有一种方法可以使用 void 指针来访问它,但效果并不完美,会出现“EXC_BAD_ACCESS”错误,这些错误根本无法被捕获和处理(尽管可能可以这样做:https://stackoverflow.com/ a/55179440/2348614)。不过,您可以访问的是类本身,这意味着您可以将类的实例存储为静态变量,从中您可以调用您的方法。 (2认同)
  • 您可以在回调中发布一个NotificationCenter,然后在应用程序中的任何位置添加一个观察者,而不是尝试访问“self”。对我有用:) (2认同)
  • 我尝试过,当应用程序在后台时它不起作用。我从 iOS 14 小部件扩展向应用程序发布了一条通知。当我在前台打开应用程序时,通知已发送,但不是之前。我认为它可以与后台模式一起使用。 (2认同)

Ron*_*ond 6

有关在主机应用程序和应用程序扩展之间进行通用双向通信的替代方法,请尝试MMWormhole:

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

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

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

该类(以及回购中的示例应用程序)似乎运行良好,并且响应很快.

我希望这也有帮助.