我正在尝试创建一个应用程序,该应用程序会定期自动登录到网站,并在相关数据已更改的情况下向他们发送本地通知。
我正在使用后台抓取来实现此目的,并且当我模拟后台抓取时,效果很好。但是,它似乎从未在物理设备上单独运行
我尝试过: *将应用程序放在手机上三天,并且至少每两小时打开一次应用程序(清醒时) *还使模拟器运行了12个小时,结果相同
我已将背景获取间隔设置为:backgroundFetchIntervalMinimum
我已将后台获取包含在info.plist
中我的代码在10秒内运行,所以我不认为长度是问题。
我使用错误的完成处理程序吗? (是否有办法在URLSession委托函数中调用.newData,.noData或.failed?) 有其他方法可以代替下载数据吗?
class AppDelegate: UIResponder, UIApplicationDelegate,
UNUserNotificationCenterDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
return true
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
print("running fetch")
let userData : [String] = {"example", "example", "example"}
let postString = "username1=\(userData[0])&text_password1=\(userData[1])&subcode=&timeoutin1=5&access1=1&city1=\(userData[2])®ion1=\(region)"
let url = URL(string: "www.example.com")!
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringCacheData, timeoutInterval: 20)
request.httpMethod = "post"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpBody = parameters.data(using: .utf8)
BackgroundSession.shared.start(request)
print("finished")
completionHandler(.newData)
}
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
if(identifier == "com.domain.app.bg") {
BackgroundSession.shared.savedCompletionHandler = completionHandler
} else {
SecondBackgroundSession.shared.savedCompletionHandler = completionHandler
}
}
}
这是我用来登录网站并解析网站响应的类 类BackgroundSession:NSObject { 静态让shared = BackgroundSession()
static let identifier = "com.domain.app.bg"
private var session: URLSession!
var savedCompletionHandler: (() -> Void)?
private override init() {
super.init()
let configuration = URLSessionConfiguration.background(withIdentifier: BackgroundSession.identifier)
session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
}
func start(_ request: URLRequest) {
print("start request")
session.downloadTask(with: request).resume()
}
func startRequest(for urlString: String, method: String, parameters: String) {
let url = URL(string: urlString)!
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringCacheData, timeoutInterval: 20)
request.httpMethod = method
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpBody = parameters.data(using: .utf8)
SecondBackgroundSession.shared.start(request)
}
}
extension BackgroundSession: URLSessionDelegate {
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
DispatchQueue.main.async {
self.savedCompletionHandler?()
self.savedCompletionHandler = nil
}
}
}
extension BackgroundSession: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
do {
let responseNS = try NSString.init(contentsOf: location, encoding: String.Encoding.utf8.rawValue)
let responseString : String = responseNS as String
let doc = try SwiftSoup.parse(responseString)
let form = try doc.select("form").first()
var action = try form!.attr("action")
action = String(action.dropFirst(2))
let url = "https://example.com" + action
let session = try form!.select("input").get(4).attr("value")
let server = try form!.select("input").get(5).attr("value")
let district = try form!.select("input").get(6).attr("value")
let stud = try form!.select("input").get(9).attr("value")
let track = try form!.select("input").get(13).attr("value")
let postString2 = "session=\(session)&server=\(server)&district=\(district)&stud=\(stud)&(track)&term=\(term)&ass="
//this starts another request that navigates to anther page on the website that displays the user data
startRequest(for: url, method: "post", parameters: postString2)
} catch {
}
}
}
这是我用来完成用户数据下载的最后一个类。和上一堂课差不多
class SecondBackgroundSession: NSObject {
static let shared = SecondBackgroundSession()
static let identifier = "com.domain.app.sc"
private var session: URLSession!
var newData = false
var savedCompletionHandler: (() -> Void)?
override init() {
super.init()
let configuration = URLSessionConfiguration.background(withIdentifier:
SecondBackgroundSession.identifier)
session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
}
func start(_ request: URLRequest) {
print("start second request")
session.downloadTask(with: request).resume()
}
extension SecondBackgroundSession: URLSessionDelegate {
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
DispatchQueue.main.async {
self.savedCompletionHandler?()
self.savedCompletionHandler = nil
}
}
}
extension SecondBackgroundSession: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
do {
let contentString = try NSString.init(contentsOf: location, encoding: String.Encoding.utf8.rawValue)
let doc : Document = try SwiftSoup.parse(contentString as String)
//class used to compare data and send notifications if anything has changed
let comp = Comparison()
comp.setElements(input: doc)
} catch {
}
}
}
该代码主要基于URLSession.datatask with request block not called in background