如何让iOS应用在Swift中每隔一分钟在后台运行?

时间:2019-06-10 09:41:09

标签: ios swift background-process

我想制作一个可以定期向网站发出HTTP请求的应用。该应用程序必须在后台运行,但可以唤醒或显示通知,具体取决于请求的响应。就像WhatsApp的消息一样,但是我没有网络服务器,只有设备会检查http get请求的值。

3 个答案:

答案 0 :(得分:4)

唯一的方法是使用静默推送通知(请参阅文档HEREHERE),它会在后台唤醒您的应用,并为您提供一些执行代码的机会一点时间。但不幸的是,它不能与本地通知一起使用,需要是推送通知。

肥胖:请注意,您的时间仅限于执行后台任务,如文档所述

  

您的应用有30秒的时间来执行任何任务并调用提供的完成处理程序

如果您发送过多的推送,iOS可以通过给应用程序小的执行优先级(甚至根本不执行它)来惩罚您的应用程序

答案 1 :(得分:2)

如果您使用静默推送通知,则应该知道静默推送对发送频率有一定限制。

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns

  

检查静默通知是否受到限制。 APN发送一个   数量有限的静默通知-使用   内容可用密钥-每天。此外,如果设备已经   超出了当天的用电预算,没有静默通知   再次发送,直到功率预算重置为止(每天一次)。   从Xcode测试应用程序时,这些限制已禁用。

并且如果应用程序强制退出,也不要进入应用程序。

如果需要保证交付,则应使用VoIP推送通知。 但是您需要苹果的理由,以及为什么需要VoIP推送。

但是您会不断消耗电池电量,这对您的用户而言并不友好。

答案 2 :(得分:1)

有可能使用无声推送通知,您可以得到此答案。

import Firebase
import UserNotifications



@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var dataManager = DataManager()
    var reloadSign = false;


    let gcmMessageIDKey = "gcm.message_id"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:
        [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        Fabric.with([Crashlytics.self])
        // Override point for customization after application launch.

        IQKeyboardManager.shared.enable = true
        DropDown.startListeningToKeyboard()

        FirebaseApp.configure()
        Messaging.messaging().delegate = self


        UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]

//        //Solicit permission from user to receive notifications
        UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { (_, error) in
            guard error == nil else{
               print(error!.localizedDescription)
                return
            }
       }
//        
//        //get application instance ID
        InstanceID.instanceID().instanceID { (result, error) in
            if let error = error {
                print("Error fetching remote instance ID: \(error)")
           } else if let result = result {
                print("Remote instance ID token: \(result.token)")
            }
        }

       application.registerForRemoteNotifications()


        return true
    }



    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
           let proj = Project()
            proj.checkData()

        }

        // Print full message.
        print(userInfo)

    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
    }


    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

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

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.

    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.

        let ud  = UserDefaults.standard
        ud.set( true, forKey: "isTerminated");
        ud.synchronize()

    }

    func crashlyticsDidDetectReport(forLastExecution report: CLSReport, completionHandler: @escaping (Bool) -> Void) {
        completionHandler(true)
    }


}

extension AppDelegate: UNUserNotificationCenterDelegate{
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo

        // With swizzling disabled you must let Messaging know about the message, for Analytics
        // Messaging.messaging().appDidReceiveMessage(userInfo)
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)

        // Change this to your preferred presentation option
        completionHandler([])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)

        completionHandler()
    }

}

extension AppDelegate: MessagingDelegate{

    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")

        let dataDict:[String: String] = ["token": fcmToken]
        NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
        // TODO: If necessary send token to application server.
        // Note: This callback is fired at each app startup and whenever a new token is generated.
    }

    func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
        print("Received data message: \(remoteMessage.appData)")
    }
}