从今天的扩展(Widget)在主机应用程序中执行操作而无需打开应用程序ios

我想从今天的扩展(Widget)pipe理包含应用程序的一些行动。

完整描述:在我的包含应用程序,一些行动(如播放/暂停audio)执行。 并希望从今天的扩展(小部件)pipe理该行动。 一个动作继续在后台状态下执行。

在今天的延期,同样的行动将执行。 因此,如果在主要包含的应用程序已经启动一个动作并将其发送到后台状态,用户可以暂停一个小部件的动作。 并且用户也可以随时从小部件(今天的扩展)开始/暂停动作。

为了实现这个目标,我使用了具有应用程序组function的UserDefault,并存储了一个布尔值。 当小部件呈现它检查布尔值和设置button状态播放/暂停。 它设置正确,但当我按扩展button行动不执行主机应用程序。

码:

在主要包含应用程序代码

override func viewDidLoad() { super.viewDidLoad() let objUserDefault = UserDefaults(suiteName:"group.test.TodayExtensionSharingDefaults") let objTemp = objUserDefault?.object(forKey: "value") self.btnValue.isSelected = objTemp NotificationCenter.default.addObserver(self, selector: #selector(self.userDefaultsDidChange), name: UserDefaults.didChangeNotification, object: nil) } func userDefaultsDidChange(_ notification: Notification) { let objUserDefault = UserDefaults(suiteName: "group.test.TodayExtensionSharingDefaults") objUserDefault?.synchronize() let objTemp = objUserDefault?.object(forKey: "value") self.btnValue.isSelected = objTemp } 

在扩展类中:

 @IBAction func onPlayPause(_ sender: UIButton) { DispatchQueue.main.async { let sharedDefaults = UserDefaults(suiteName: "group.test.TodayExtensionSharingDefaults") if let isPlaying = sharedDefaults?.bool(forKey: "isPlaing") { sharedDefaults?.set(!isPlaying, forKey: "isPlaying") }else{ sharedDefaults?.set(false, forKey: "isPlaying") } sharedDefaults?.synchronize() } 

当用户更新默认值时不会触发通知。 它的应用程序重新启动时更新的值。

那么如何解决这个问题呢?

同样的事情想要从包含应用程序到一个部件相反的意思。 (容易用户单一的行动对象,但如何?)

还有其他的方式来执行一个快速的行动,包含应用程序从扩展名,而无需打开应用程序?

使用MMWormhole (或其新的和非官方的Swift版本,只是Wormhole )。 这很简单。

在应用的视图控制器中:

 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let wormhole = MMWormhole(applicationGroupIdentifier: "group.test.TodayExtensionSharingDefaults", optionalDirectory: "TodayExtensionSharingDefaults") wormhole.listenForMessage(withIdentifier: "togglePlayPause") { [weak self] _ in guard let controller = self else { return } controller.btnValue.isSelected = controller.btnValue.isSelected } } 

在扩展中:

 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view from its nib. self.wormhole = MMWormhole(applicationGroupIdentifier: "group.test.TodayExtensionSharingDefaults", optionalDirectory: "TodayExtensionSharingDefaults") } @IBAction func onPlayPause(_ sender: UIButton) { guard let wormhole = self.wormhole else { extensionContext?.openURL(NSURL(string: "foo://startPlaying")!, completionHandler: nil) } // Throw error here instead of return, since somehow this function was called before viewDidLoad (or something else went horribly wrong) wormhole.passMessageObject(nil, identifier: "togglePlayPause") } 

在Xcode的Document Types部分,在URLs下声明foo:// (或者其他你使用的),然后在你的AppDelegate实现application(_:open:options:) ,以便当传递的URL是foo://startPlaying

如何将URL添加到Xcode

  1. 创build自定义url

  2. 检查组数据(你设置是否正确)

  3. 每当你点击button,主机应用程序将从AppdelegateUIApplication委托调用

     func application(_ application: UIApplication, open urls: URL, sourceApplication: String?, annotation: Any) -> Bool { let obj = urls.absoluteString.components(separatedBy: "://")[1] NotificationCenter.default.post(name: widgetNotificationName, object: obj) print("App delegate") return true } 
  4. 从那里发出通知,然后在hostapp的任何地方观察它。

    小部件button操作代码

     @IBAction func doActionMethod(_ sender: AnyObject) { let button = (sender as! UIButton) var dailyThanthi = "" switch button.tag { case 0: dailyThanthi = "DailyThanthi://h" case 1: dailyThanthi = "DailyThanthi://c" case 2: dailyThanthi = "DailyThanthi://j" // case 3: // dailyThanthi = "DailyThanthi://s" // case 4: // dailyThanthi = "DailyThanthi://s" default: break } let pjURL = NSURL(string: dailyThanthi)! self.extensionContext!.open(pjURL as URL, completionHandler: nil) } 
  5. 查看自定义urltypes: https : //developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html

  6. 注意:

    应用程序扩展程序与其包含的应用程序之间没有直接的联系; 通常情况下,包含的应用程序甚至没有运行,而包含的扩展正在运行。 包含应用程序和主机应用程序的应用程序扩展程序完全不能进行通信。

    在典型的请求/响应事务中,系统代表主机应用程序打开应用程序扩展,在主机提供的扩展上下文中传输数据。 该扩展程序显示用户界面,执行一些工作,并且如果适合扩展的目的,则将数据返回给主机。

    图2-2中的虚线表示应用扩展程序与其包含的应用程序之间的有限交互。 “今日”小部件(并没有其他应用程序扩展types)可以通过调用NSExtensionContext类的openURL:completionHandler:方法来要求系统打开其包含的应用程序。 如图2-3中的读/写箭头所示,任何应用程序扩展及其包含的应用程序都可以访问私有定义的共享容器中的共享数据。 图2-3中以简单的forms展示了扩展程序,其主机应用程序及其包含的应用程序之间的完整通信词汇表。

    https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html