Выполните действие в хост-приложении из расширения Today (Widget) без открытия приложения ios
Я хочу управлять некоторыми действиями в приложении с сегодняшним расширением (Widget).
Полное описание:
в моем поддерживающем приложении выполняются некоторые действия (например, воспроизведение/пауза аудио). И хотите управлять этим действием и с сегодняшнего расширения (виджет). Действие также продолжает выполняться в фоновом состоянии.
В сегодняшнем расширении будет выполнено одно и то же действие. поэтому для этого, если в основном содержащем приложении уже запускается действие и отправляется в фоновое состояние, пользователь может приостановить действие из виджета. и пользователь также может запускать/приостанавливать действие в любое время из виджета (сегодняшнее расширение).
Для достижения этой цели я использовал UserDefault с возможностью группы приложений и сохранил одно логическое значение. когда присутствует виджет, он проверяет логическое значение и устанавливает состояние воспроизведения/паузы в кнопке. он установлен правильно, но когда я нажимаю кнопку кнопки расширения, действие не выполняется в главном приложении.
код:
в главном коде приложения
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()
}
уведомление не было запущено, когда пользователь обновил значение по умолчанию. он обновляет значение, когда приложение перезагружается.
как решить эту проблему?
и то же самое хочет сделать в противоположном смысле от содержания приложения к виджету.
(простой пользовательский объект с одним действием, но как?)
И любой другой способ выполнить быстрое действие в приложении приложения из расширения без открытия приложения?
Ответы
Ответ 1
Используйте 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")
}
Объявите foo://
(или что-то еще, что вы используете) в разделе "Типы документов Xcode" в разделе "URL-адреса", а затем выполните application(_:open:options:)
в своем AppDelegate
, чтобы приложение начало воспроизводить музыку, когда переданный URL был foo://startPlaying
.
![как добавить URL-адрес в Xcode]()
Ответ 2
-
Создать пользовательский URL-адрес Sceheme
-
Проверьте данные групп (вы устанавливаете правильно или нет)
-
Всякий раз, когда вы нажимаете кнопку, хост-приложение будет вызвано из Appdelegate, UIApplication делегировать
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
}
-
Огоньте свое уведомление, а затем наблюдайте за ним в любом месте вашего хостап.
Виджет Действие кнопки 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)
}
-
Проверьте тип пользовательского URL:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html
-
Примечание:
Прямой связи между расширением приложения и его приложение; обычно приложение, содержащее приложение, даже не работает выполняется расширенное расширение. Расширения приложений, содержащие приложение и приложение-хост вообще не связывается.
В типичной транзакции запроса/ответа система открывает расширение приложения от имени хост-приложения, передавая данные в расширение контекст, предоставленный хостом. Расширение отображает пользовательский интерфейс, выполняет определенную работу и, при необходимости, для целей расширения, возвращает данные хосту.
Пунктирная линия на рисунке 2-2 представляет собой ограниченное взаимодействие между расширением приложения и его содержащим приложением. Сегодня виджет (и другой тип расширения приложения) может попросить систему открыть его приложение, вызвав метод openURL:completionHandler:
класс NSExtensionContext
. Как указано стрелками чтения/записи в Рисунок 2-3. Любое расширение приложения и его приложение могут обращаться к общим данных в отдельном контейнере общего доступа. Полный словарь связь между расширением, его хост-приложением и его содержанием приложение показано в простой форме на рисунке 2-3.
https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html