Error 400: Remote Push Notifications Not Working For iOSby
In my localhost server, remote push notifications worked fine. It had stopped working on the production server. I have designed a neat system to separate the development environment from production mode for testing remote push notifications. Different certificates are used automatically based on the running environment. Device tokens are stored in a database based on the nature of the iOS app’s distribution. It ensures sandbox mode uses debug-version of device tokens else we will be running often into the “Baddevice Token” response from the apns server.
The system is well-tested with time. Remote push notifications stopped working in production mode all of sudden. I am not using the third-party service to manage our push notifications. I have our well-designed and well-tested middleware to manage push notifications. It follows a modern recommendation from apple to use http/2 to process all requests to apns server. Many good tutorials out there on the subject. I will share my troubleshooting experience and its solutions.
I turned on the verbose settings to display every information of cURL execution. It gives insight on if the connection is going through the apns server and what response we get.
CURLOPT_VERBOSE => true
I sent a dummy push notification to the device using its correct device token in the production environment. There were verbose logs in my terminal. Connection passed successfully through apns production gateway. My server does support Http/2 and there was no problem there too. Response log after execution did throw 400 error. 400 is a bad request.
Apple has provided the documentation to troubleshoot the meaning of every error code returned by apns. 400 error code has various list of reasons. For example:
- Baddevice Token
- Missing Device Token
- Bad Certificate Environment
- ….etc etc
Check the link of all possible error codes and their reasons. This is very helpful. My verbose just gave the code but the not specific reason. There is a various reasons for 400 but I need specific to find my problem. In my backend code, I dumped the value of the response from apns and found out the reason.
The reason was “Missing Topic”.
The sandbox environment doesn’t complain about “Missing Topic” but the production environment does. I created a header supplying “Missing Topic”. I passed this header array to CURLOPT_HTTPHEADER
$header = array( “apns-topic” => “com.example.app", “apns-push-type” => “alert" );
The value of apns-topic will be the app’s bundle id. Fired another round of testing. This didn’t work. I got a “Missing Topic” error. I went through the documentation carefully and realised that I have to send the values as literal strings, not in key-value pairs of PHP’s associative array.
$header = array( “apns-topic: com.example.app”, “apns-push-type: alert” ); $curlconfig = array( …… …… CURLOPT_HTTPHEADER => $header, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0, CURLOPT_VERBOSE => true );
See the difference? That’s it. Problem solved.