#ios #swift #background #refresh
#iOS #swift #фон #обновить
Вопрос:
Новичок пытается создать приложение, которое выдает пользователю случайное «слово дня».
В ходе тестирования я понял, что приложение должно открываться пользователем каждый день, чтобы вручную запускать функцию isRefreshRequired()
(которая извлекает новое слово и обновляет пользовательский интерфейс и содержимое уведомлений). Но мне нужно, чтобы это делалось автоматически, независимо от того, открывает пользователь приложение или нет.
Возможно ли это вообще? Я застрял между тем, какие методы использовать:
-
NSCalendarDayChanged. Я нашел этот полезный ответ, но я не уверен, где он будет реализован? Если я использую его applicationDidFinishLaunching, где будет вызываться функция calendarDayDidChange()? В viewDidLoad()?
-
significantTimeChangeNotification() — возможно, лучший метод? Опять же, не уверен, как это реализовать и где. В документе также говорится:
Если устройство находится в спящем режиме, когда меняется день, это уведомление будет опубликовано при пробуждении.
Означает ли пробуждение при повторном открытии приложения? Потому что я хочу, чтобы функция isRefreshRequired() выполнялась, даже если пользователь не касался приложения.
- Обновление фонового приложения: это не кажется полезным, поскольку для этого требуется URLSession, и пользователь, возможно, отключил фоновое обновление. Кажется немного чрезмерным для приложения, которое просто хочет дать пользователю новое слово!
Рассматриваемый код:
override func viewDidLoad() {
super.viewDidLoad()
isRefreshRequired()
}
func isRefreshRequired() {
// if it is first time opening app
if userDefaults.bool(forKey: "First Launch") == false {
//run code during first launch
_ = updateWordOfTheDay()
NotificationManager.askNotificationPermission()
print("First time opening app")
userDefaults.set(true, forKey: "First Launch")
}
else {
//run code after first launch
print("Not first time opening app")
userDefaults.set(true, forKey: "First Launch")
let lastAccessDate = userDefaults.object(forKey: "lastAccessDate") as? Date ?? Date()
userDefaults.set(Date(), forKey: "lastAccessDate")
// if it is the same day give the vocab picked for that day
if calendar.isDateInToday(lastAccessDate) {
readFromUserDefaults()
print("No refresh required as it is the same day as lastAccessDate which was (lastAccessDate)")
}
else {
print("new day since lastAccessDate")
_ = updateWordOfTheDay()
}
}
}
func sendNotification(using: ChineseVocab) {
let center = UNUserNotificationCenter.current()
center.removeAllDeliveredNotifications()
center.removeAllPendingNotificationRequests()
let content = UNMutableNotificationContent()
content.title = using.Chinese " " using.Pinyin
content.body = using.Definition
}
func saveToUserDefaults(with data: ChineseVocab) {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(data) {
userDefaults.set(encoded, forKey: "selectedVocab")
}
}
func readFromUserDefaults() {
if let savedVocab = userDefaults.object(forKey: "selectedVocab") as? Data {
let decoder = JSONDecoder()
if let wordOfTheDay = try? decoder.decode(ChineseVocab.self, from: savedVocab) {
updateLabels(using: wordOfTheDay)
NotificationManager.sendNotification(using: wordOfTheDay)
print("readFromUserDefaults() is working: (wordOfTheDay)")
} else {
print("unable to load readFromUserDefaults()")
}
}
}
Ответ №1:
То, что вы пытаетесь сделать, это вызвать функцию, когда приложение закрыто или работает в фоновом режиме. Делая шаг назад, пользователь фактически не использует ваше приложение в данный момент. Поэтому из-за этого ваше приложение также не должно запускать функции. Я считаю, что это сделано специально, чтобы телефон мог выделять ресурсы для приложений / функций, которые активно использует пользователь.
Таким образом, невозможно просто вызвать функцию, когда приложение закрыто. Но отступая от ваших пунктов выше:
-
Я думаю, что использование applicationDidBecomeActive или applicationDidFinishLaunching, вероятно, ваш лучший выбор. Это функции в AppDelegate, и вы можете напрямую вызывать функции в методах. applicationDidBecomeActive будет выполняться каждый раз, когда приложение появляется на экране. Если вам это нужно только на одном экране, вы можете просто вызвать viewDidAppear / viewWillAppear ViewController вместо этого.
-
Idk что-нибудь о significantTimeChangeNotification, поэтому я не хочу говорить вам, что это не сработает, но я бы предположил, что уведомление не будет выполняться, если приложение закрыто.
-
Обновление фонового приложения — это в основном то, что вы пытаетесь сделать, однако, даже если вы его реализуете .. оно будет выполняться только тогда, когда приложение работает в фоновом режиме. Если приложение полностью закрыто, фоновая выборка вызываться не будет. Поэтому я бы предположил, что большую часть времени он все равно не будет вызываться.
Комментарии:
1. Спасибо за ваш отзыв! Если в принципе невозможно обновить данные при закрытии приложения, как работает большинство приложений? Есть много приложений «слово дня», которые я скачал для сравнения, и все они каждый день отправляют пользователю новое слово, даже если приложение не было открыто. Как они это делают?
2. Я предполагаю, что когда вы говорите, что они «отправляют пользователю новое слово», оно приходит в виде push-уведомления? Вы можете подключить внешние push-уведомления, подключив свое приложение к стороннему бэкэнду, такому как Google Firebase. И оттуда вы можете запускать «облачные функции», которые выполняются независимо от вашего приложения и могут отправлять push-уведомления на устройства. Но вы упомянули, что вы новичок, и я бы пока воздержался от этого. Это не очень просто реализовать, и облачные функции написаны не на Swift (я думаю, обычно на JavaScript).
3. Для ваших целей, если вы запускаете функции в applicationDidBecomeActive, в любое время, когда пользователь открывает приложение, оно будет немедленно обновляться.
4. Я использую локальные уведомления, но, полагаю, другие приложения используют push-уведомления? Проблема в том, что содержимое уведомления должно быть новым словом. Если приложение открывается не каждый день, содержимое уведомления — это просто старое слово за предыдущий день / всякий раз, когда приложение открывалось в последний раз: (
5. Я считаю, что локальные уведомления (если они не запланированы) выполняются только тогда, когда приложение находится в фоновом режиме, а не закрыто. Поэтому, как только он закроется, они не будут выполняться. Если вы заранее знаете, какие слова будут обозначать, например, следующую неделю или месяц, вы можете запланировать кучу локальных уведомлений, когда пользователь открывает приложение (на следующую неделю или месяц). Конечно, вам нужно будет заранее установить все время уведомления и содержимое. developer.apple.com/documentation/usernotifications /…