I'm trying to send a remote notification from own php server to app.
Here's the code in AppDelefate.m:
#import "AppDelegate.h"
#import <UserNotifications/UserNotifications.h>
#interface AppDelegate ()
#end
#implementation AppDelegate
#define SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[self registerForRemoteNotifications];
return YES;
}
- (void)registerForRemoteNotifications {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if(!error){
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}];
}
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSLog(#"User Info : %#",notification.request.content.userInfo);
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}
//Called to let your app know which action was selected by the user for a given notification.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
NSLog(#"User Info : %#",response.notification.request.content.userInfo);
completionHandler();
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"%#", userInfo);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"%#", userInfo);
completionHandler(UIBackgroundFetchResultNewData);
}
- (void)applicationDidFinishLaunching:(UIApplication *)app {
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
// Handle remote notification registration.
- (void)application:(UIApplication *)app
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
NSString *token = [[devToken description] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#"<>"]];
token = [token stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"content---%#", token);
}
- (void)application:(UIApplication *)app
didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(#"Remote notification support is unavailable due to error: %#", err);
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
#end
When I run the app, it ask for notification privilege, after accepted. Console print the following token:
content---13eeb8d33de4f0ba55f520469f9b0970e973faa6904a38428b2193b04ac3782b
So I use this token in my PHP server for testing:
<?php
// Put your device token here (without spaces):
$deviceToken = '13eeb8d33de4f0ba55f520469f9b0970e973faa6904a38428b2193b04ac3782b';
// Put your private key's passphrase here:
$passphrase = 'xoxoxo';
// Put your alert message here:
$message = 'Test push.';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'BDSPKCertificates.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
var_dump($ctx);
// Open a connection to the APNS server
$apns = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx); // production
echo "<p>Open Connection</p>";
if(!$apns)
{
echo "<p>Failed to connect!<br />Error Number: " . $err . " <br />Code: " . $errstr . "</p>";
return;
}
else
{
echo "<p>Connected</p>";
// Create the payload body
$body = array();
$body['aps'] = array(
"title"=>"Test title",
'alert' => $message,
'sound' => 'default',
'badge' => 1
);
// Encode the payload as JSON
$payload = json_encode($body);
echo "<p>Message: ";
print_r($payload);
echo "</p>";
// Build the binary notification
$msg = chr(0) . pack("n",32) . pack('H*',str_replace(' ', '', $deviceToken)) . pack ("n", strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($apns, $msg, strlen($msg));
if (!$result)
{
echo 'Message not delivered' . PHP_EOL;
}
else
{
echo 'Message successfully delivered' . PHP_EOL;
}
// Close the connection to the server
fclose($apns);
}
?>
When i run this PHP code, it prints the following:
resource(2) of type (stream-context)
Open Connection
Connected
Message: {"aps":{"title":"Test title","alert":"Test push.","sound":"default","badge":1}}
Message successfully delivered
However my app receive nothing. Please help me to find what is missing in my codes. Thanks.
please confirm, you have open 2195 port in server firewall. Apple push notification sent via 2195 port. So it should open.
I think you are using sandbox environment but in your PHP script your socket client is production, use sandbox for development like below.
Sandbox
ssl://gateway.sandbox.push.apple.com:2195'
// Open a connection to the APNS server
$apns = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx); // sandbox
Production
ssl://gateway.push.apple.com:2195'
// Open a connection to the APNS server
$apns = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx); // production
Related
I'm having some problems with my implementation because it crash in a random way after 400 - 500 sendings.
I was wondering why the best APNS tutorials for PHP and other platforms advice you to sleep a little (o a lot!) after sending some messages to the APNS server.
Why to sleep your code when sending iOS Push Notifications?
The crash I get is
<html><head><title>500 Internal Server Error</title></head><body>
<h1>Internal Server Error</h1>
<p><i>stream_socket_client(): php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known</i></p>
<p>#0 /Users/MyUser/development/projects/project/project-api/helpers/PushNotificationHelper.php:407 stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195',0,'',60,5,NULL)<br />...
My source code:
static function pushIOS($ios_devices, $push_type, $data_array){
$log = new Logger('PushConsumer');
$log->pushHandler(new StreamHandler(BASEPATH.'log/push.log', Logger::DEBUG));
// set time limit to zero in order to avoid timeout
set_time_limit(0);
// this is the pass phrase you defined when creating the key
$passphrase = 'mypass';
// load your device ids to an array
$deviceIds = $ios_devices;
// this is where you can customize your notification
//payload = '{"aps":{"alert":"' . $message . '","sound":"default"}}';
$msg = array
(
'type' => $push_type,
'message' => $data_array,
);
$payload = json_encode($msg);
$result = 'Start' . '<br />';
////////////////////////////////////////////////////////////////////////////////
// start to create connection
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', BASEPATH.'scripts/certificates/appleck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$log->addDebug(count($deviceIds)." devices will receive notifications.'");
//echo count($deviceIds) . ' devices will receive notifications.<br />';
// Open a connection to the APNS server
$fp = stream_socket_client(F3::get('apns_url'), $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp) {
$log->addDebug("Failed to connect: $err $errstr");
exit("Failed to connect: $err $errstr" . '<br />');
} else {
$log->addDebug("Apple service is online.");
foreach ($deviceIds as $item) {
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $item) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result) {
$log->addDebug("Undelivered message to push token: $item");
//echo 'Undelivered message count: ' . $item . '<br />';
} else {
$log->addDebug("Delivered message to push token: $item");
//echo 'Delivered message count: ' . $item . '<br />';
}
}
fclose($fp);
$log->addDebug("The connection has been closed by the client");
}
$log->addDebug(count($deviceIds)." devices have received notifications");
// wait for some time
sleep(2);
}
The line with the crash:
$fp = stream_socket_client(F3::get('apns_url'), $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx);
I am following this tutorial to make APN service available for my app
here are the methods in AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil )
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let token = deviceToken.description.stringByReplacingOccurrencesOfString(" ", withString: "")
print("Got token data! \(token)")
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print("Couldn't register: \(error)")
}
Once I ran the app I've been prompted to enable push notification from this app and I enabled it .
I have got the device token printed in the console
then I've used this php code to send the notification :
<?php
// Put your device token here (without spaces):
$deviceToken = 'c1d7b8960fb94d633e9fbf2e7d2aa0748be4b3e32dc3869a0125ca607813e8a1';
// Put your private key's passphrase here:
$passphrase = "xxxxxxxxxx";
// Put your alert message here:
$message = 'My first push notification!';
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'sound' => 'default'
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
// Close the connection to the server
fclose($fp);
In the terminal I ran php phpfilename.php then I got
Connected to APNS
Message successfully delivered
But I didn't get the notification ever ,
Further more , I have used this app and It shows this error :
Notification error: APN invalid token
I am trying to implement push notification in iOS in PHP using APNS library. Here is my code :
<?php
// Put your device token here (without spaces):
$deviceToken = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
// Put your private key's passphrase here:
$passphrase = 'XXXXXX';
// Put your alert message here:
$message = 'My first push notification!';
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'Certificates.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'sound' => 'default'
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));print_r($result);
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
// Close the connection to the server
fclose($fp);
?>
It show message sending successfully but in iOS it does not show notification.
2015-07-28 08:32:39 Connected to APNS result = 97
2015-07-28 08:32:39 Message successfully delivered
2015-07-28 08:32:39 Connection closed to APNS
Why this is happening? Am I missing anything ?
his mistake is with the ios 9 if so stop using the code in objective C and use in swift as it has a bug in generating objectiv token - C for ios9.
I recommend urgent change your code.
Also through this thought was the server when the scheduled ios changed for swift everything was resolved and my php was almost equal.
Care:
$ msg = chr (0). pack ('N', 32). pack (H * ','. '$deviceToken [0].'). pack ('N', strlen ($ payload)). $ payload;
There are two potential reason that is causing this:
Your app is in foreground
Your device token is invalid
In my app. I am directly getting deviceToken that's in NSData
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *deviceTokenString = [NSString stringWithFormat:#"%#", deviceToken];
// this is producing something like:
// <xxxxxxx 9b0f527f xxxxxxxx 2727ed28 xxxxxxxx 4e693a61 xxxxxxx ac2f7dbb>
//
// and i am directly saving that to my servers database
Here's what i have in my server.
$from_database = "<xxxxxxx 9b0f527f xxxxxxxx 2727ed28 xxxxxxxx 4e693a61 xxxxxxx ac2f7dbb>";
// this removes the '<' and '>' to make the device token valid
//
$token_string = substr($from_database, 1, -1);
$token_array[] = $token_string;
// you can also add multiple 'token_string' to the 'token_array' for push notification broadcasting, i am currently doing that and it is working properly.
...
public function __push_notification($message_input, $token_array)
{
$message = stripslashes($message_input);
$passphrase = 'xxxxxx';
$cert = realpath('xxx.pem');
$payload = '{
"aps" :
{
"alert" : "'.$message.'",
"badge" : 1,
"sound" : "bingbong.aiff"
}
}';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $cert);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
{
// echo "Failed to connect $err $errstr <br>";
return;
}
else
// echo "Post notification sent<br>";
$dev_array = array();
$dev_array = $token_array;
foreach ($dev_array as $device_token)
{
$msg = chr(0) .
pack("n", 32) .
pack('H*', str_replace(' ', '', $device_token)) .
pack("n", strlen($payload)) .
$payload;
// echo "sending message :" . $payload . "n";
fwrite($fp, $msg);
}
fclose($fp);
}
Also check this, might be helpful: Facing problems in ios push notification php code
I would like to get ready for production with APNS, and I am assuming the best (only, easiest?) way is to store the device IDs that sign up for push in a database (assuming SQL) and then having the PHP script (somehow?) send it to all of them (for loop?) instead of just one (deviceToken - mine)like I have now.
This is what I currently have in my AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Let the device know we want to receive push notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
return YES;
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSLog(#“Token: %#", deviceToken);
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(#"Failed to get token, error: %#", error);
}
So here I am just logging the users deviceToken, and then I manually copied and pasted that into my PHP script which goes something like this:
<?php
// Put your device token here (without spaces):
$deviceToken = '[device token here]';
// Put your private key's passphrase here:
$passphrase = '[passphrase here]';
// Put your alert message here:
$message = 'Hello, there!';
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'sound' => 'default'
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
// Close the connection to the server
fclose($fp);
So what I need help with is making a connection to my server's database (MySQL) and storing the deviceToken. Then I need to loop the PHP into sending the notification to all the devices.
Let me know if I need to clarify on anything.
Thank you.
For storing device token in your MySQL database, you must create a seperate API.
For Ex. calling http://example.com/saveDeviceToken with device token.
At the time notification registration(didRegisterForRemoteNotificationsWithDeviceToken), you must call this API with parameter as your device token.
In this API you can fetch the device token and save it to your database.
Then in your above code you just fetch the device token from your DB.
I am using a PHP script to send push notifications to my device. Here is what I use
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'sound' => 'default',
'id' => '10'
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
echo "to $deviceToken.";
// Close the connection to the server
fclose($fp);
I get it successfully. I tap the view button, and I am trying to read the 'id' variable like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Check for push notification info
NSDictionary *pushInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (pushInfo)
{
// TODO: Pull the poke's info from our server and update the UI to display it
NSLog(#"Here's the id: %#", [pushInfo valueForKey:#"id"]);
}
return YES;
}
However, I don't get a NSLog when in mutitasking. I have yet to try it when I close the app because I cannot run console after you close out.
I even tried this:
- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif {
// Handle the notificaton when the app is running
NSLog(#"Recieved Notification %#",notif);
}
If I send the notification when running, I don't even get a NSLog. What's going on?
Thanks in advance!
NSDictionary *pushInfo = [launchOptions valueForKey:#"UIApplicationLaunchOptionsRemoteNotificationKey"] objectForKey:#"aps"]];