richsage / RMSPushNotificationsBundle

NOT MAINTAINED! ⛔️ Push notifications/messages for mobile devices. Supports iOS, Android (C2DM, GCM), Blackberry and Windows Mobile (toast only). A Symfony2 bundle.
MIT License
321 stars 152 forks source link

GCM Android working randomly on production #66

Closed Kaz- closed 9 years ago

Kaz- commented 10 years ago

Hi ! My script sending Android notifications works perfectly on my dev server, and when I'm migrating it to production, it works like 1 times on 20, the other times :

 $this->container->get('rms_push_notifications')->send($push)

is returning false ...

I think it's not related to my GCM or bundle configuration, because it's exactly the same on dev server, and it works perfectly...

CURL is installed and php5-curl too, and I've tried both false and true on 'use_multi_curl' ...

I'm stuck, please help.

ghost commented 9 years ago

Same here. On development it works like a charm, but now we have uploaded to production server, it doesn't work. We have the gcm ports opened (5228-5230) and it doesn't solve the problem.

Also, we have logged the response, but it only says something like app error, so it's not clear where is the problem.

Any ideas?

aroban commented 9 years ago

Same problem here, seems like guzzle response is null in AndroidGCMNotification but there's no error. ....

ghost commented 9 years ago

I solved the problem overriding the send method, using standard curl instead of buzz.... works perfect that way.

aroban commented 9 years ago

For android and ios as well ?

That's very cool,

Still not workin for me, when use multi_curl to false i get name lookup time out when it's set to true, got nothing but "Failed" from testcommande...

Maybe you could share your trick with us ?

thx.

ghost commented 9 years ago

For sure!, I only had to override the androidgcm class, with ios notifications I didn't have problems. As I said before, I override just the send method of androidgcm class, with the following.

    public function send(MessageInterface $message)
    {
        if (!$message instanceof AndroidMessage) {
            throw new InvalidMessageTypeException(sprintf("Message type '%s' not supported by GCM", get_class($message)));
        }
        if (!$message->isGCM()) {
            throw new InvalidMessageTypeException("Non-GCM messages not supported by the Android GCM sender");
        }

        $headers = array(
            "Authorization: key=" . $this->apiKey,
            "Content-Type: application/json",
        );
        $data = array_merge(
            $message->getGCMOptions(),
            array("data" => $message->getData())
        );

        // Chunk number of registration IDs according to the maximum allowed by GCM
        $chunks = array_chunk($message->getGCMIdentifiers(), $this->registrationIdMaxCount);

        // Hacemos el envío mediante cURL standard
        $this->responses = array();
        foreach ($chunks as $registrationIDs) {
            $data["registration_ids"] = $registrationIDs;
            $ch = curl_init($this->apiURL);
            $data_string = json_encode($data);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5000);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

            $this->responses[] = curl_exec($ch);
            curl_close($ch);
        }

        // Determine success
        foreach ($this->responses as $response) {
            $message = json_decode($response);
            if ($message === null || $message->success == 0 || $message->failure > 0) {
                return false;
            }
        }

        return true;
    }

Hope it helps! Cheers!

aroban commented 9 years ago

Thank you !

the code works, now its up to me to find where and how should i override this as the vendor folder should remain untouched.

ghost commented 9 years ago

Correct. The easiest way is to create a class on your bundle that inherits from the vendor's androidgcm service class overwriting the send method and then redeclare the service pointing to that class.

If you find problems just say. Good luck!

aroban commented 9 years ago

Thank you,

i'll try this today, have to deliver this week.

I alreadly created a class that extends androidmessage, but i was lookin for a way to tell the bundle to use the derived class and not the one in the original bundle.

What do you mean by redeclaring the service pointing to that class ?

thx

richsage commented 9 years ago

So, obviously I'm interested in how this can be fixed in the bundle itself, rather than overriding classes in your own code :-) particularly if the use_multi_curl option isn't making a difference. If Buzz isn't a suitable option to use, then I'm open to suggestions as to a preferred alternative. I'm less keen on using curl directly however.

aroban commented 9 years ago

I always used Guzzle for anykind of http request, maybe this can be suitable ?

The thing is that other people doesn't seem to have this problem... that's weird.

ghost commented 9 years ago

@aroban Once you have your class into (for example) src/YourBundle/Service/MyAndroidGCMClass.php, you have to declare a service that overrides the original one. You can do it in the services.yml file into app/config, adding this (assuming that you use yml configurations):

services:
...
    rms_push_notifications.android.gcm:
        class: YourBundle/Service/MyAndroidGCMClass
        arguments:
            - %rms_push_notifications.android.gcm.api_key%
            - %rms_push_notifications.android.gcm.use_multi_curl%
        tags:
            - { name: rms_push_notifications.handler, osType: rms_push_notifications.os.android.gcm }

And that's it. The bundle will use the overriden class instead the original one.

@richsage I agree with you. The weird thing is that it works on my local development environment, but not into production server... maybe it's a server configuration or firewall problem, but sometimes you can't deal with that kind of problems with 3rd party servers, that's why I had to override the code.

richsage commented 9 years ago

@aroban I'll take a look at Guzzle, I haven't used it in earnest yet but maybe it's a better alternative

@davidfernandezperrino sure, that is strange though - I'm using it in production without any issue but I don't remember doing any "different" configuration. For now, I guess overriding is OK then :-)

aroban commented 9 years ago

Well,

i'm almost there.

here's what i've tried

$message = new AndroidMessage();
        $message->setGCM(true);
        $message->setDeviceIdentifier('mydeviceid');
        $message->setMessage('this is a test');
        $gcmObject = $this->getContainer()->get('rms_push_notifications');
        echo get_class($gcmObject);
        $response = $gcmObject->send($message);

The echo returns "RMS\PushNotificationsBundle\Service\Notifications"

I've overrided/extended RMS\PushNotificationsBundle\Service\OS\AndroidGCMNotification with this class whic resides in my bundle/service folder

class AndroidGCMNotification extends RMS\PushNotificationsBundle\Service\OS\AndroidGCMNotification
{

    public function send(MessageInterface $message)
    { 
        exit("OK Override");
    }
}

But my send method get never called which seems normal according to the previous echo

and finally i created services.yml both in app/config/services.yml and in my bundle/resources/config/services.yml

which contains the following

services:
    rms_push_notifications.android.gcm:
           class: MyVendor\CoreBundle\Service\AndroidGCMNotification
           arguments:
               - %rms_push_notifications.android.gcm.api_key%
               - %rms_push_notifications.android.gcm.use_multi_curl%
           tags:
               - { name: rms_push_notifications.handler, osType: rms_push_notifications.os.android.gcm }

Not sure which class to override. I would like to let the RMS\PushNotificationsBundle\Service\Notifications class handling notification type and get the correct handler (in its send method) but once the correct handler found. It should use my androiGcmNotification and not the bundle default one here on Notifications.php line 37 :

 return $this->handlers[$message->getTargetOS()]->send($message);
ghost commented 9 years ago

It looks correct to me. You are redeclaring the service with the class that extends RMS\PushNotificationsBundle\Service\OS\AndroidGCMNotification class.

As you well said, the vendor choose the handler to use. If it is the androidgcm handler, and the service is well redeclared, it will use your class and not the vendor's one. Remember to clear the cache.

aroban commented 9 years ago

yep cleared the cache and still not working...

aroban commented 9 years ago

The problem seems to be the service which is bad registred

in Notifications.php i dumped the handlers ( $this->handlers )

and the class for android.gcm is the following

[rms_push_notifications.os.android.gcm] => RMS\PushNotificationsBundle\Service\OS\AndroidGCMNotification Object

So i guess that my service overriding is not well wrote or wrote in the bad file.

ghost commented 9 years ago

Maybe the service name is rms_push_notifications.os.android.gcm instead of rms_push_notifications.android.gcm???

aroban commented 9 years ago

Found it !

the service overriding declaration must be in app/config.yml and not in app/services.yml nor in bundle/resources/services.yml

Was declaring the service in the wrong place.

it works now ! very great !

thanks a lot

ghost commented 9 years ago

Glad to hear that! I have the service redeclared in app/config/services.yml, and it works too.

Cheers!

andrewsmm commented 9 years ago

I had same problem. Problem resolve when change timeout from 5 seconds to 30 in Buzz. vendor/kriswallsmith/buzz/lib/Buzz/Client/AbstractClient.php

protected $timeout = 30;

Will we add this setting timeout: 30 in config.yml ?

richsage commented 9 years ago

Configuring timeouts is a PR open at #84 - any feedback welcome!