當您發送推送通知,有幾個問題:
如果有問題,蘋果將斷開你,但你不知道關於它。當您使用基本通知時,無法知道它們是否全部發送。 解決方案:這是使用增強通知然後檢查錯誤響應的全部要點。請注意,我們將在數據庫查詢中使用「ORDER BY id」,然後使用該ID作爲我們在通知中發送的標識符。這樣,如果出現問題,我們確切知道數據庫中的哪一行導致了問題(因此我們知道Apple何時斷開連接並停止發送通知)。然後,我們可以繼續將推送通知發送到導致問題的行後面的所有行,而不必重新發送到已發送給我們的行。
如果一切正常,Apple不會發送任何迴應,因此,當fread()正在等待未到達的數據時,可能會導致腳本暫停並等待一段時間。 解決方案:需要將stream_set_blocking設置爲0,以便fread總是立即返回。請注意,這會導致fread在接收到錯誤響應之前返回的另一個小問題,但請在代碼中查看解決方法,該代碼僅暫停1/2秒後完成所有發送,然後再次檢查fread 。
您可以發送多個推送通知,比發送錯誤響應要快得多。 解決方案:再次,這是上述相同的解決方法...暫停1/2秒後,所有的發送完成,然後再檢查一次fread。
這是我使用PHP的解決方案,它解決了我遇到的所有問題。它非常基本,但完成了工作。我已經通過一次發送幾個通知來測試它,並且一次發送了12萬個通知。
<?php
/*
* Read Error Response when sending Apple Enhanced Push Notification
*
* This assumes your iOS devices have the proper code to add their device tokens
* to the db and also the proper code to receive push notifications when sent.
*
*/
//database
$host = "localhost";
$user = "my_db_username";
$pass = "my_db_password";
$dbname = "my_db_name";
$con = mysql_connect($host, $user, $pass);
if (!$con) {
die('Could not connect to database: ' . mysql_error());
} else {
mysql_select_db($dbname, $con);
}
// IMPORTANT: make sure you ORDER BY id column
$result = mysql_query("SELECT id,token FROM `device_tokens` ORDER BY id");
//Setup notification message
$body = array();
$body['aps'] = array('alert' => 'My push notification message!');
$body['aps']['notifurl'] = 'http://www.myexampledomain.com';
$body['aps']['badge'] = 1;
//Setup stream (connect to Apple Push Server)
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'passphrase', 'password_for_apns.pem_file');
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns.pem');
$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
stream_set_blocking ($fp, 0); //This allows fread() to return right away when there are no errors. But it can also miss errors during last seconds of sending, as there is a delay before error is returned. Workaround is to pause briefly AFTER sending last notification, and then do one more fread() to see if anything else is there.
if (!$fp) {
//ERROR
echo "Failed to connect (stream_socket_client): $err $errstrn";
} else {
$apple_expiry = time() + (90 * 24 * 60 * 60); //Keep push alive (waiting for delivery) for 90 days
//Loop thru tokens from database
while($row = mysql_fetch_array($result)) {
$apple_identifier = $row["id"];
$deviceToken = $row["token"];
$payload = json_encode($body);
//Enhanced Notification
$msg = pack("C", 1) . pack("N", $apple_identifier) . pack("N", $apple_expiry) . pack("n", 32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n", strlen($payload)) . $payload;
//SEND PUSH
fwrite($fp, $msg);
//We can check if an error has been returned while we are sending, but we also need to check once more after we are done sending in case there was a delay with error response.
checkAppleErrorResponse($fp);
}
//Workaround to check if there were any errors during the last seconds of sending.
usleep(500000); //Pause for half a second. Note I tested this with up to a 5 minute pause, and the error message was still available to be retrieved
checkAppleErrorResponse($fp);
echo 'DONE!';
mysql_close($con);
fclose($fp);
}
//FUNCTION to check if there is an error response from Apple
// Returns TRUE if there was and FALSE if there was not
function checkAppleErrorResponse($fp) {
//byte1=always 8, byte2=StatusCode, bytes3,4,5,6=identifier(rowID). Should return nothing if OK.
$apple_error_response = fread($fp, 6);
//NOTE: Make sure you set stream_set_blocking($fp, 0) or else fread will pause your script and wait forever when there is no response to be sent.
if ($apple_error_response) {
//unpack the error response (first byte 'command" should always be 8)
$error_response = unpack('Ccommand/Cstatus_code/Nidentifier', $apple_error_response);
if ($error_response['status_code'] == '0') {
$error_response['status_code'] = '0-No errors encountered';
} else if ($error_response['status_code'] == '1') {
$error_response['status_code'] = '1-Processing error';
} else if ($error_response['status_code'] == '2') {
$error_response['status_code'] = '2-Missing device token';
} else if ($error_response['status_code'] == '3') {
$error_response['status_code'] = '3-Missing topic';
} else if ($error_response['status_code'] == '4') {
$error_response['status_code'] = '4-Missing payload';
} else if ($error_response['status_code'] == '5') {
$error_response['status_code'] = '5-Invalid token size';
} else if ($error_response['status_code'] == '6') {
$error_response['status_code'] = '6-Invalid topic size';
} else if ($error_response['status_code'] == '7') {
$error_response['status_code'] = '7-Invalid payload size';
} else if ($error_response['status_code'] == '8') {
$error_response['status_code'] = '8-Invalid token';
} else if ($error_response['status_code'] == '255') {
$error_response['status_code'] = '255-None (unknown)';
} else {
$error_response['status_code'] = $error_response['status_code'] . '-Not listed';
}
echo '<br><b>+ + + + + + ERROR</b> Response Command:<b>' . $error_response['command'] . '</b> Identifier:<b>' . $error_response['identifier'] . '</b> Status:<b>' . $error_response['status_code'] . '</b><br>';
echo 'Identifier is the rowID (index) in the database that caused the problem, and Apple will disconnect you from server. To continue sending Push Notifications, just start at the next rowID after this Identifier.<br>';
return true;
}
return false;
}
?>
嗨。我實現了你在我的(工作)推動者類中的代碼。奇怪的是,我從來沒有得到蘋果的迴應。 $ apple_error_response始終是false。但是一些推送消息被傳遞,有些只是失敗。你有什麼想法,爲什麼我沒有得到任何迴應? – 2013-09-16 12:54:43
我這將近一年發佈半前和使用推送通知後沒多久,所以我真的不記得我所討論的問題停止。爲了調試創建你知道的令牌列表,然後複製令牌並進行修改,以便它們失敗(所以5已知好&5已知壞)。然後,一旦您接受設備上的推送通知並確認已收到推送通知,請禁用該設備上的推送通知,並查看當您嘗試再次發送該令牌時會發生什麼。同時檢查Apple的文檔以確保他們沒有改變他們的服務器響應方式。 – jsherk 2013-09-16 17:05:44
感謝您的回答。我不得不把睡眠時間增加到一秒鐘,然後它(大部分)工作。但我仍然不確定在這個時候答案會在那裏。所以我做了一個循環,每50毫秒檢查一次答案,如果5秒後它完全沒有響應,它將返回。 – 2013-09-17 07:59:17