APNS 只显示一个未决通知
APNS shows just one pending notification
我已经成功地为我的 ios 应用实现了推送通知服务。我已经生成了所需的证书并且代码有效。当设备与互联网断开连接并收到一些通知(未显示且未显示)时出现问题,然后当设备再次连接到互联网时......只有一个未决 apns 显示推送通知。我使用 php 作为后端,使用 NotificationServiceExtension 作为附件等
这是我的 php 代码
public static function sendAPNS($token,$data)
{
print_r($token);
$apnsServer = 'ssl://gateway.push.apple.com:2195';
$privateKeyPassword = 'password-here';
/* Device token */
$deviceToken = $token;
$pushCertAndKeyPemFile = 'nameofthefile.pem';
$stream = stream_context_create();
stream_context_set_option($stream, 'ssl', 'passphrase', $privateKeyPassword);
stream_context_set_option($stream, 'ssl', 'local_cert', $pushCertAndKeyPemFile);
$connectionTimeout = 20;
$connectionType = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
$connection = stream_socket_client($apnsServer, $errorNumber, $errorString, $connectionTimeout, $connectionType, $stream);
/*Alert array eg. body, title etc */
$alertArray = [];
$alertArray["body"] = $data["body"];
$alertArray["title"] =$data["title"];
$messageBody['aps'] = array(
'alert' => $alertArray,
'sound' => 'default',
'category'=> 'customUi',
'mutable-content'=>1
);
/*User Info*/
$messageBody["attachment-url"] = $data["url"];
$messageBody["type_code"] = $data["type_code"];
$messageBody["ref_id"] = $data["ref_id"];
$messageBody["user_to"] =$data["user_to"];
/*Could be here*/
$payload = json_encode($messageBody);
print_r($payload);
$notification = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
$wroteSuccessfully = fwrite($connection, $notification, strlen($notification));
fclose($connection);
}
我的服务扩展如下:-
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
var defaultsUser: UserDefaults = UserDefaults(suiteName: "group.shared.com.plates215")!
if let countNot = defaultsUser.value(forKey: "notUniversal")
{
var IntcountNot = countNot as! Int
IntcountNot = IntcountNot + 1
var sum: NSNumber = NSNumber(value: IntcountNot)
bestAttemptContent.badge = sum
defaultsUser.set(IntcountNot, forKey: "notUniversal")
}
if let photo = bestAttemptContent.userInfo["attachment-url"] as? String
{
updateReadNots(userID: (bestAttemptContent.userInfo["user_to"] as? String)!)
let url = NSURL(string: photo);
var err: NSError?
var imageData :NSData = try! NSData(contentsOf: url! as URL)
var bgImage = UIImage(data:imageData as Data)
if let attachment = UNNotificationAttachment.create(identifier: "colo", image: bgImage!, options: nil)
{
bestAttemptContent.attachments = [attachment]
contentHandler(bestAttemptContent)
}
}
}
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
func updateReadNots(userID: String)
{
var url: String = "api-url"
let session: URLSession = URLSession(configuration: URLSessionConfiguration.default)
var urlDown = URL(string: url)
let downloadTask = session.downloadTask(with: urlDown!) { (url, rsp, error) in
}
downloadTask.resume()
}
}
extension UNNotificationAttachment {
static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
do {
try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
let imageFileIdentifier = identifier+".png"
let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
guard let imageData = UIImagePNGRepresentation(image) else {
return nil
}
try imageData.write(to: fileURL)
let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
return imageAttachment
} catch {
print("error " + error.localizedDescription)
}
return nil
}
}
解决方案
根据@Li Sim 的 link,这就是我所做的......我的每条通知
从我的服务器发送的不仅包含最新通知,还包含
每个未读通知都由“\n”分隔。然后 ios
通知正确显示它们。跟踪已读和未读
通知,我在 back_end 中保留了一个 read_status 键
在收到通知后立即更新
NotificationContentExtension
(https://developer.apple.com/documentation/usernotifications/unnotificatio nserviceextension)。用于修改内容和执行一些代码
每当收到 apns 推送时。希望这对将来的人有帮助
:)
这是 Apple 之前记录的行为。
Link 记录:https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
If a device is offline, sending a notification request targeting that device causes the previous request to be discarded. If a device remains offline for a long time, all its stored notifications in APNs are discarded.
虽然我对此不熟悉,但(对此感到抱歉)这里有一些 post 我发现对您的问题有用:
希望您能从中有所收获。我能想到的另一种方法是使用离线兼容的 LocalNotifications,但您必须想出一种方法来跟踪用户未阅读的通知。 (也许是某种身份)
我已经成功地为我的 ios 应用实现了推送通知服务。我已经生成了所需的证书并且代码有效。当设备与互联网断开连接并收到一些通知(未显示且未显示)时出现问题,然后当设备再次连接到互联网时......只有一个未决 apns 显示推送通知。我使用 php 作为后端,使用 NotificationServiceExtension 作为附件等
这是我的 php 代码
public static function sendAPNS($token,$data)
{
print_r($token);
$apnsServer = 'ssl://gateway.push.apple.com:2195';
$privateKeyPassword = 'password-here';
/* Device token */
$deviceToken = $token;
$pushCertAndKeyPemFile = 'nameofthefile.pem';
$stream = stream_context_create();
stream_context_set_option($stream, 'ssl', 'passphrase', $privateKeyPassword);
stream_context_set_option($stream, 'ssl', 'local_cert', $pushCertAndKeyPemFile);
$connectionTimeout = 20;
$connectionType = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
$connection = stream_socket_client($apnsServer, $errorNumber, $errorString, $connectionTimeout, $connectionType, $stream);
/*Alert array eg. body, title etc */
$alertArray = [];
$alertArray["body"] = $data["body"];
$alertArray["title"] =$data["title"];
$messageBody['aps'] = array(
'alert' => $alertArray,
'sound' => 'default',
'category'=> 'customUi',
'mutable-content'=>1
);
/*User Info*/
$messageBody["attachment-url"] = $data["url"];
$messageBody["type_code"] = $data["type_code"];
$messageBody["ref_id"] = $data["ref_id"];
$messageBody["user_to"] =$data["user_to"];
/*Could be here*/
$payload = json_encode($messageBody);
print_r($payload);
$notification = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
$wroteSuccessfully = fwrite($connection, $notification, strlen($notification));
fclose($connection);
}
我的服务扩展如下:-
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
var defaultsUser: UserDefaults = UserDefaults(suiteName: "group.shared.com.plates215")!
if let countNot = defaultsUser.value(forKey: "notUniversal")
{
var IntcountNot = countNot as! Int
IntcountNot = IntcountNot + 1
var sum: NSNumber = NSNumber(value: IntcountNot)
bestAttemptContent.badge = sum
defaultsUser.set(IntcountNot, forKey: "notUniversal")
}
if let photo = bestAttemptContent.userInfo["attachment-url"] as? String
{
updateReadNots(userID: (bestAttemptContent.userInfo["user_to"] as? String)!)
let url = NSURL(string: photo);
var err: NSError?
var imageData :NSData = try! NSData(contentsOf: url! as URL)
var bgImage = UIImage(data:imageData as Data)
if let attachment = UNNotificationAttachment.create(identifier: "colo", image: bgImage!, options: nil)
{
bestAttemptContent.attachments = [attachment]
contentHandler(bestAttemptContent)
}
}
}
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
func updateReadNots(userID: String)
{
var url: String = "api-url"
let session: URLSession = URLSession(configuration: URLSessionConfiguration.default)
var urlDown = URL(string: url)
let downloadTask = session.downloadTask(with: urlDown!) { (url, rsp, error) in
}
downloadTask.resume()
}
}
extension UNNotificationAttachment {
static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
do {
try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
let imageFileIdentifier = identifier+".png"
let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
guard let imageData = UIImagePNGRepresentation(image) else {
return nil
}
try imageData.write(to: fileURL)
let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
return imageAttachment
} catch {
print("error " + error.localizedDescription)
}
return nil
}
}
解决方案
根据@Li Sim 的 link,这就是我所做的......我的每条通知
从我的服务器发送的不仅包含最新通知,还包含
每个未读通知都由“\n”分隔。然后 ios
通知正确显示它们。跟踪已读和未读
通知,我在 back_end 中保留了一个 read_status 键
在收到通知后立即更新
NotificationContentExtension
(https://developer.apple.com/documentation/usernotifications/unnotificatio nserviceextension)。用于修改内容和执行一些代码
每当收到 apns 推送时。希望这对将来的人有帮助
:)
这是 Apple 之前记录的行为。 Link 记录:https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
If a device is offline, sending a notification request targeting that device causes the previous request to be discarded. If a device remains offline for a long time, all its stored notifications in APNs are discarded.
虽然我对此不熟悉,但(对此感到抱歉)这里有一些 post 我发现对您的问题有用:
希望您能从中有所收获。我能想到的另一种方法是使用离线兼容的 LocalNotifications,但您必须想出一种方法来跟踪用户未阅读的通知。 (也许是某种身份)