【问题标题】:How to communicate between iOS App Containing Extension and Extension (not Host App)如何在iOS App Containing Extension和Extension(不是Host App)之间进行通信
【发布时间】:2015-01-16 16:19:39
【问题描述】:

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

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

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

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

【问题讨论】:

标签: ios core-data swift nsnotificationcenter ios-extensions


【解决方案1】:

TLDR:不,但有一个 hack

iOS 应用程序没有真正的进程间通信,无论是否有扩展。 NSDistributedNotification 还没有从 OS X 迁移到 iOS,而且可能不会。

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

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

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

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

【讨论】:

  • 我试图用 open() + 一些标志来观察文件系统的变化,但没有成功。我不知道 NSFilePresenter!这很好用,谢谢!
  • Ludovic Landry,能否举例说明您是如何成功实现这种通信的?非常感谢
  • 如果我的包含应用程序没有运行(终止),presentedItemDidChange 会启动/唤醒包含应用程序吗?
  • 如果应用没有运行,它不会收到通知。不过,无论如何,您的应用在启动时都需要加载文件内容,因此它不需要该通知来查找最新数据。
【解决方案2】:

您可以使用一种 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

【讨论】:

  • 好吧,只是一个警告——你不能在回调中访问“self”。有一种方法可以使用 void 指针来访问它,但这也不能很好地工作,出现“EXC_BAD_ACCESS”错误,根本无法捕获和处理(尽管可以这样做:stackoverflow.com/a/55179440/2348614)。但是,您可以访问的是类本身,这意味着您可以将类的实例存储为静态变量,从中可以调用您的方法。
  • 建议先检查实例是否存在。此外,这个类将无法 deinit(),因为它的引用仍然被硬绑定到静态变量中,所以它会在你的记忆中存在。只有当您覆盖/取消静态实例变量或手机内存不足并开始左右杀死东西时,它才会被取消初始化。
  • 您可以在回调中发布 NotificationCenter,然后在应用程序的任何位置添加观察者,而不是尝试访问“self”。为我工作:)
  • 我试过了,当应用程序在后台时它不起作用。我将来自 iOS 14 小部件扩展的通知发布到应用程序。当我在前台打开应用程序时,通知已发送,但之前未发送。我认为它适用于背景模式。
【解决方案3】:

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

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

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

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

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

我希望这也有帮助。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-02
      • 1970-01-01
      • 2017-04-22
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多