简体   繁体   English

从今日扩展(小部件)在主机应用程序中执行操作,无需打开应用程序ios

[英]Perform action in host app from Today extension(Widget) Without opening app ios

I want to manage some action in containing app from today extension(Widget). 我想在今天的扩展程序(Widget)中管理包含应用程序的一些操作。

Full description: in my containing app, some action (like play/pause audio) perform. 完整描述:在我的包含应用程序中,执行一些操作(如播放/暂停音频)。 And want to manage that action also from today extension(widget). 并希望从今天的扩展(小部件)管理该操作。 An action continues to perform in background state as well. 动作也继续在后台状态下执行。

In today extension, the same action will perform. 在今天的扩展中,将执行相同的操作。 so for that, if in the main containing app already starts an action and send it into background state, a user can pause action from a widget. 因此,如果在主要包含应用程序中已经启动操作并将其发送到后台状态,则用户可以暂停窗口小部件的操作。 and the user also can start/pause action any time from the widget (today extension). 并且用户还可以随时从小部件(今天的扩展)开始/暂停操作。

For achieve this goal I used UserDefault with app Group capability and store one boolean value. 为了实现这个目标,我使用UserDefault和app Group功能并存储一个布尔值。 when widget present it checks boolean value and set button state play/pause. 当小部件出现时,它检查布尔值并设置按钮状态播放/暂停。 it's set correctly but when I press extension button action does not perform in host app. 它设置正确,但当我按下扩展按钮时,操作无法在主机应用程序中执行。

code: 码:

in main containing app code 在主要包含应用程序代码

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
  }

In Extension Class: 在扩展类中:

@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()
}

notification was not fired when a user updates default. 用户更新默认值时未触发通知。 it's updated value when the app restarts. 它是应用重启时的更新值。

so how to solve this issue? 那么如何解决这个问题呢?

and the same thing wants to do in opposite means from containing app to a widget. 同样的事情想要从包含应用程序到小部件的相反方式做。 (easy to user single action object but how?) (易于用户单个动作对象,但如何?)

And is any other way to perform a quick action in containing app from extension without opening App? 还有其他方法可以在不打开App的情况下从扩展程序中包含应用程序的快速操作吗?

Use MMWormhole (or its new and unofficial Swift version, just Wormhole ). 使用MMWormhole (或其新的和非官方的Swift版本,只是Wormhole )。 It's very simple. 这很简单。

In the app's view controller: 在应用程序的视图控制器中:

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
    }
}

In the extension: 在扩展中:

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")
}

Declare foo:// (or whatever else you use) in Xcode's Document Types section, under URLs, then implement application(_:open:options:) in your AppDelegate so that the app starts playing music when the URL passed is foo://startPlaying . 在Xcode的文档类型部分中,在URL下声明foo:// (或者你使用的任何其他内容),然后在AppDelegate实现application(_:open:options:) ,以便当传递的URL为foo://startPlaying时应用程序开始播放音乐foo://startPlaying

如何将URL添加到Xcode

  1. Create Custom URL Sceheme 创建自定义URL场景

  2. Check groups data.(are you setting correct or not) 检查组数据。(你设置是否正确)

  3. Whenever you click on button, the host app will get called from Appdelegate , UIApplication delegate 每当您单击按钮时,将从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. Fire your notification from there then observe it anywhere in your hostapp. 从那里发出通知,然后在你的hostapp的任何地方观察它。

    Widget Button action code 小部件按钮动作代码

     @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. Check out custom url type: https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html 查看自定义网址类型: https//developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html

  6. Note: 注意:

    There is no direct communication between an app extension and its containing app; 应用扩展程序与其包含应用程序之间没有直接通信; typically, the containing app isn't even running while a contained extension is running. 通常,包含的应用程序在运行包含的扩展时甚至不运行。 An app extension's containing app and the host app don't communicate at all. 包含应用和主机应用的应用扩展程序根本不进行通信。

    In a typical request/response transaction, the system opens an app extension on behalf of a host app, conveying data in an extension context provided by the host. 在典型的请求/响应事务中,系统代表主机应用程序打开应用程序扩展,在主机提供的扩展上下文中传送数据。 The extension displays a user interface, performs some work, and, if appropriate for the extension's purpose, returns data to the host. 扩展程序显示用户界面,执行一些工作,并且,如果适合扩展程序的目的,则将数据返回到主机。

    The dotted line in Figure 2-2 represents the limited interaction available between an app extension and its containing app. 图2-2中的虚线表示应用扩展程序与其包含应用程序之间可用的有限交互。 A Today widget (and no other app extension type) can ask the system to open its containing app by calling the openURL:completionHandler: method of the NSExtensionContext class. “今日”窗口小部件(并且没有其他应用程序扩展类型)可以通过调用NSExtensionContext类的openURL:completionHandler:方法来要求系统打开其包含的应用程序。 As indicated by the Read/Write arrows in Figure 2-3, any app extension and its containing app can access shared data in a privately defined shared container. 如图2-3中的读/写箭头所示,任何应用程序扩展及其包含的应用程序都可以访问私有定义的共享容器中的共享数据。 The full vocabulary of communication between an extension, its host app, and its containing app is shown in simple form in Figure 2-3. 扩展,其主机应用程序及其包含应用程序之间的完整通信词汇在图2-3中以简单的形式显示。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM