Могу ли я сделать вызов API, когда пользователь завершает приложение?

Мне нужно сделать вызов API, когда пользователь завершает приложение (принудительное закрытие). Прямая реализация, которую я сделал, как показано ниже.

В делегате приложения я добавил следующий код.

func applicationWillTerminate(_ application: UIApplication) {
    print("________TERMINATED___________")
    testAPICall()
}

func testAPICall(){
    let url = getURL()
    let contentHeader = ["Content-Type": "application/json"]
    Alamofire.request(url,
                  method: .put,
                  parameters: ["username": "abc@xyz.com"],
                  encoding: JSONEncoding.default,
                  headers: contentHeader).responseJSON { (response) -> Void in
                    print("-----")
                  }
}

Однако звонок не делается. И, просматривая документацию, я обнаружил, что у меня есть всего 5 секунд для выполнения задачи в этом методе, и, прежде всего, выполнение вызова API не является задачей, которую нужно выполнить здесь. Поэтому мне интересно, как бы это сделать.

3 ответа

Решение

Это двойной вопрос

Этап 1. Обеспечение запуска API-вызова каждый раз, когда пользователь завершает работу приложения / до того, как оно становится активным

Вы всегда можете использовать expiration handler фоновый режим iOS application В вашем приложении

объявлятьvar bgTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier(rawValue: 0);

и в вашем приложении

 func applicationDidEnterBackground(_ application: UIApplication) {

    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

    bgTask = application.beginBackgroundTask(withName:"MyBackgroundTask", expirationHandler: {() -> Void in
        // Do something to stop our background task or the app will be killed
        application.endBackgroundTask(self.bgTask)
        self.bgTask = UIBackgroundTaskIdentifier.invalid
    })

    DispatchQueue.global(qos: .background).async {
        //make your API call here
    }
    // Perform your background task here
    print("The task has started")
}

Фоновый обработчик истечения срока действия гарантирует, что у вас будет достаточно времени для запуска вызова API каждый раз, когда вы ставите приложение неактивным или прекращаете работу.

Этап 2. Обеспечение успешного завершения вызова API

Хотя обработчик истечения может гарантировать, что у вас будет достаточно времени для запуска вызова API, он не может гарантировать успешное завершение вызова API. Что делать, если вызов API занимает больше времени, а запрос находится в полете, а время истекает?

Единственный способ обеспечить успешное выполнение вызова API - это убедиться, что используется правильная конфигурация для URLSession

Согласно документам

Фоновые сеансы позволяют выполнять загрузку и выгрузку контента в фоновом режиме, пока ваше приложение не запущено.

ссылка: https://developer.apple.com/documentation/foundation/nsurlsession?language=objc

Так что используйте фоновый сеанс и используйте задачу загрузки. Вместо того, чтобы иметь простой API get / post, к которому вы будете обращаться с каким-либо параметром, попросите вашего бэкэнд-разработчика принять файл и поместить все ваши параметры в этот файл (если есть) и запустить задачу загрузки с фоновым сеансом.

Как только задача загрузки начинается с фонового сеанса, iOS позаботится о ее завершении (если, конечно, вы не попадете в задачу аутентификации) даже после того, как ваше приложение будет убито.

Я считаю, что это самое близкое, что вы можете получить, чтобы гарантировать запуск вызова API и завершение его завершения, когда приложение становится неактивным / завершается. У меня вроде была дискуссия с разработчиком Apple относительно того же самого, и они согласились, что это может быть вероятным решением:)

Надеюсь, поможет

Основная идея - сделать вызов синхронизации до завершения работы приложения.

func applicationWillTerminate(_ application: UIApplication) {

     let semaphore: dispatch_semaphore_t = dispatch_semaphore_create(0)
     let request = NSMutableURLRequest(URL:url)
     let task = NSURLSession.sharedSession().dataTaskWithRequest(request, 
                     completionHandler: {
            taskData, _, error -> () in

            dispatch_semaphore_signal(semaphore);
      })
      task.resume()
      dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}

вот простой способ выполнить эту задачу -

      func applicationWillTerminate(_ application: UIApplication) {
    
let sem = DispatchSemaphore(value: 0)
startSomethingAsync(completionHandler: {

sem.signal()//When task complete then signal will call
 })
sem.wait()//waiting until task complete
}
Другие вопросы по тегам