Swift; HTTP-запрос от UNUserNotificationCenter не работает: подключение к Интернету отключено
Я использую Xcode Version 9.4.1 (9F2000)
,
У меня есть этот код в AppDelegate.swift
:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
showPushButtons()
return true
}
func httpRequest(file: String, postKey1: String, postValue1: String, postKey2: String, postValue2: String) {
let url = URL(string: "https://www.example.com/\(file)")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = "\(postKey1)=\(postValue1)&\(postKey2)=\(postValue2)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(String(describing: responseString))")
}
task.resume()
}
func showPushButtons(){
let replyAction = UNTextInputNotificationAction(
identifier: "reply.action",
title: "Reply to message",
textInputButtonTitle: "Send",
textInputPlaceholder: "Write some text here")
let pushNotificationButtons = UNNotificationCategory(
identifier: "allreply.action",
actions: [replyAction],
intentIdentifiers: [],
options: [])
UNUserNotificationCenter.current().setNotificationCategories([pushNotificationButtons])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
if response.actionIdentifier == "reply.action" {
if let textResponse = response as? UNTextInputNotificationResponse {
let sendText = textResponse.userText
print("Received text message: \(sendText)")
httpRequest(file: "message.php", postKey1: "message", postValue1: "Hello!", postKey2: "chat_user", postValue2: "Peter")
}
}
completionHandler()
}
Что оно делает:
При получении push-уведомления и принудительном касании появится текстовое поле и клавиатура (как известно из приложений для обмена сообщениями, таких как WhatsApp). Вы можете написать текст и отправить / отправить его.
Вы можете получить и распечатать это сообщение с этой строкой:
print("Received text message: \(sendText)")
Это работает без проблем.
Но при попытке отправить данные на мой сервер так:
httpRequest(file: "message.php", postKey1: "message", postValue1: "Hello!", postKey2: "chat_user", postValue2: "David")
это не работает. Нет доступа к моему серверу, и я получаю сообщения об ошибках в журнале консоли:
Полученное текстовое сообщение: Первая попытка
2018-07-19 08:45:00.643935+0200 MyApp[4307:1502538] +[CATransaction синхронизации] вызывается внутри транзакции
2018-07-19 08:45:00.644639+0200 MyApp[4307:1502538] +[синхронизация CATransaction], вызываемая внутри транзакции
2018-07-19 08:45:13.091958+0200 MyApp[4307:1502647] Ошибка TIC TCP Conn [1: 0x1c4169a80]: 1:50 Err (50)
2018-07-19 08: 45: 13.093089 + 0200 MyApp [4307: 1502647] Задача <1E8151BB-7098-46CD-9F68-8AA0E320CB7D>.<1> Ошибка загрузки HTTP (код ошибки: -1009 [1:50])
Полученное текстовое сообщение: вторая попытка
2018-07-19 08:45:13.094756+0200 MyApp[4307:1503029] Задание <1E8151BB-7098-46CD-9F68-8AA0E320CB7D>.<1> завершено с ошибкой - код: -1009
2018-07-19 08: 45: 13.096208 + 0200 MyApp [4307: 1502538] + [CATransaction synchronize], вызываемый внутри транзакции
2018-07-19 08:45:13.096580+0200 MyApp[4307:1502538] +[синхронизация транзакции] вызвана в транзакции ошибка = Необязательно (Ошибка домена =NSURLErrorDomain Code=-1009 "Интернет-соединение не работает." UserInfo={NSUnderlyingError=0x1cc047320 {Домен ошибки =kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, NSErrorFailingURLrp.KF : //www.example.com/message.php, _kCFStreamErrorDomainKey = 1, _kCFStreamErrorCodeKey = 50, NSLocalizedDescription = Интернет-соединение отключено от сети.})
Моя функция httpRequest()
кажется, работает, потому что я могу, например, позвонить из didFinishLaunchingWithOptions
как это:
httpRequest(file: "message.php", postKey1: "message", postValue1: "Hello!", postKey2: "chat_user", postValue2: "David")
без каких-либо проблем. Это также означает, что мой домен и мой сервер работают нормально.
Но почему я не могу позвонить httpRequest()
функция от моего UNUserNotificationCenter
функционировать?
При получении push-уведомления мое приложение, конечно, находится в фоновом режиме или закрыто. Нужен ли какой-то специальный код, чтобы он работал в фоновом режиме или около того?
2 ответа
Вот мой рабочий код от AppDelegate.swift
:
// AppDelegate.swift
import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
pushAction()
return true
}
func registerForPushNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
print("\nPermission granted: \(granted)\n")
self.pushAction()
guard granted else { return }
self.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("\nNotification settings: \(settings)\n")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications()
})
}
}
func httpRequest(file: String, postKey1: String, postValue1: String, postKey2: String, postValue2: String) {
let url = URL(string: "https://www.example.com/\(file)")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = "\(postKey1)=\(postValue1)&\(postKey2)=\(postValue2)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("\nerror=\(String(describing: error))\n")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("\nstatusCode should be 200, but is \(httpStatus.statusCode)\n")
print("\nresponse = \(String(describing: response))\n")
}
let responseString = String(data: data, encoding: .utf8)
print("\nresponseString = \(String(describing: responseString))\n")
}
task.resume()
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
let token = tokenParts.joined()
print("\nDevice Token: \(token)\n")
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("\nFailed to register: \(error)\n")
}
func pushAction(){
let replyAction = UNTextInputNotificationAction(
identifier: "reply.action",
title: "Reply to message",
options:[],
textInputButtonTitle: "Send",
textInputPlaceholder: "Input/write text here")
let pushNotificationButtons = UNNotificationCategory(
identifier: "allreply.action",
actions: [replyAction],
intentIdentifiers: [],
options: [])
UNUserNotificationCenter.current().setNotificationCategories([pushNotificationButtons])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// If you don’t want to show notification when app is open, do something else here and make a return here.
// Even if you don’t implement this delegate method, you will not see the notification on the specified controller. So, you have to implement this delegate and make sure the below line execute. i.e. completionHandler.
completionHandler([.sound,.alert,.badge])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
if response.actionIdentifier == "reply.action" {
if let textResponse = response as? UNTextInputNotificationResponse {
if UIApplication.shared.applicationState != .active{
self.registerBackgroundTask()
}
let sendText = textResponse.userText
print("\nReceived text message: \(sendText)\n")
DispatchQueue.global(qos: .background).async {
self.httpRequest(file: "message.php", postKey1: "message", postValue1: sendText, postKey2: "user", postValue2: "Peter")
}
}
}
completionHandler()
}
func registerBackgroundTask() {
backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
self?.endBackgroundTask()
}
assert(backgroundTask != UIBackgroundTaskInvalid)
}
func endBackgroundTask() {
print("\nBackground task ended.\n")
UIApplication.shared.endBackgroundTask(backgroundTask)
backgroundTask = UIBackgroundTaskInvalid
}
}
Не забывайте:
- Создать push-сертификат
- Вы увидите свой токен устройства в журнале консоли
- Добавлять "category":"allreply.action"
в вашей полезной нагрузки APS, как это:
{
"aps":{
"alert":{
"title":"Hello",
"body":"This is a test!"
},
"badge":0,
"sound":"default",
"category":"allreply.action"
}
}
включить Push Notifications
а также Background Modes
в Capabilities
:
Большое спасибо Раза К. от Freelancer.com!
Вы должны перейти к вашему info.plist
и добавьте "Настройки безопасности транспорта приложений" в "Список свойств информации", затем нажмите знак плюс рядом с настройками безопасности транспорта приложений, добавьте к нему "Разрешить произвольные загрузки" и измените значение на "ДА".
надеюсь, это поможет вам