我可以在用户终止应用程序时拨打 api 电话吗?

Can I make an api call when the user terminates the app?

我需要在用户终止应用程序(强制关闭)时进行 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("-----")
                  }
}

但是,没有拨打电话。通过 documentation,我发现我只有 5 秒才能完成此方法中的任务,最重要的是,进行 api 调用不是此处要完成的任务。所以我想知道,这样做的方法是什么。

这是一个双重问题

第 1 阶段:确保 API 调用在用户每次终止应用程序时开始/在它变为活动状态之前开始

您始终可以在您的 appdelegate

中使用 iOS applicationexpiration handler 后台模式

声明 var bgTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier(rawValue: 0);

在你的 appdelegate 中

 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

使用正确的配置

根据文档

Background sessions let you perform uploads and downloads of content in the background while your app isn't running.

link: https://developer.apple.com/documentation/foundation/nsurlsession?language=objc

所以利用后台会话并使用上传任务。与其使用普通的 get/post API ,你会用一些参数来命中,而是让你的后端开发人员接受一个文件并将所有参数数据放入该文件(如果有的话)并开始上传具有后台会话的任务。

一旦上传任务以后台会话开始,iOS 将处理它的完成(除非你显然以身份验证挑战告终),即使你的应用已被终止。

我认为这是您可以确保启动 API 调用并确保在应用程序获得 inactive/terminated 后完成调用的最接近方法。我与一位苹果开发者就此进行了讨论,他们同意这可能是一个可能的解决方案:)

希望对您有所帮助

这里的主要思想是在应用程序终止之前进行同步调用

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

提示:

调度信号量是传统计数信号量的有效实现。只有当调用线程需要被阻塞时,调度信号量才会向下调用内核。如果调用信号量不需要阻塞,则不会进行内核调用。

通过调用 signal() 方法增加信号量计数,通过调用 wait() 或其指定超时的变体之一减少信号量计数。

这里是实现这个任务的简单方法-

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
}