Logo Gaby Becker

IMDb Kino App für die Kinovorschau
Locus Maps App - Offline Maps + Geocaching
WordPress App zum Blogartikel schreiben von unterwegs
Play Music - App - der Musicplayer für unterwegs
Google Currents Feedreader für Android

Sending Push notifications of Drupal 7 to registered Android smartphones

android_oma's picture

Add a Service part 1Since early May (2013) our Webgrrls Events app is available in playstore. Originally, it was designed so that the user himself get the events after pressing refresh button. By this action  we wanted to prevent using the webservices when there is no internet. 

The user had to update the events time to time, and it was not a nice thing to do. To save the user from doing the above task, we came up with the idea of the GCM [Google Cloud Mwssaging]. The GCM service ensbles you to send messages to each registered device via push messages. In our case such a message would be setting a new event or change an existing one.
 
To connect Drupal with Android is quite tricky. After severela trial we proceeded as the following.
 
there were 3 modules which were installed
  • 1. Services (essential because it provides the availability of the REST server )

               install services module

              install module push-notifications

  • 3. GCM [Google Cloud Messaging] (to control the sending of messages using the Rules)

               install gcm module

 
Setting up the modules
 
  • 1.1 enable services 
  • 1.2 Enable REST-server
  • 1.3 Setting up endpoints

               add a service part 1

              add a service part 2

              add a service part 3

              add a service part 4

              add a service part 5

              add a service part 6

              add a service part 7

              configure push notifications module part 1

              configure push notifications module part 2

              configure push notifications module part 3

  • 2.1 In addition, the user rights for Push Notifications must be set up so that guests can also send Notifications - so that the registration id if the device can be stored.
  • 3. setting up the GCM

              configure gcm module

  • 3.1 Setting up the Rules
  • 3.1.1 Rule for the sending of messages

              create rule for registration part 1

              create rule for registration part 2

              create rule for registration part 3

              create rule for registration part 4

  • 3.1.2 Rule for a notification when registrations ids are no longer active, so they can be deleted from the database.

              create rule for unregistration

              create rule for unregistration part 2

 
At this point  everything is done at the Drupal site already. Now we need to establish the GCM on the Android App page. We will discuss more on this later.
I found a little bug in GCM-Module, Which was notified to the developer via Drupal.org and Twitter. He was extrelemely fast fixing the bug and created a new version for installation. 
Then I had the stupid idea to change the code from the GCM module itself, because I wanted to get the RegistrationIds [token field here] from the database table for the push notifications module. In the native mode of the GCM module the IDs are - comma separated.

The developer also had the good idea: easy to use PHP code in the text field of the token.

I was not aware until this email in text format that I can use this in each and any text field, if "PHP code" is enabled [only for admins]. In the rules I had an action "Execute custom PHP code". But I could not use because the GCM module did not provide this.

So it was easier to use php code into the tokens-field.

Here is the PHP code in the action token field.
 
This code, I tried first, will not run. The function GROUP_CONCAT can only be used for a defined field-length [I have read length from 521 until 1024]. For our tokens-field it is too short. 
 

<?php $result = db_query("SELECT GROUP_CONCAT(token SEPARATOR  ',') FROM {push_notifications_tokens}")->fetchField();  echo $result; ?>  

For this reason at least I used this code into the tokens-field of the rule:

<?php
$tokens = "";
$result = db_query("SELECT token FROM {push_notifications_tokens}");
while($row = $result->fetchAssoc()) {
    $tokens .= $row['token'] . ", ";
}
$tokens = substr($tokens, 0, strlen($tokens) - 1);
echo $tokens; 
?>

So I read all the tokens in the form of a comma-separated list. Exactly what is expected in the field. Deleting the  inactive ids I have not yet implemented.
At present this is still easily doable manually by deleting the tokens in the database table.
 
Now the todos for the Android side. 
Here the previously generated endpoint, the URL and the project number must be passed so that the notifications can be processed. 
An extract from the Code can be found here:
The URLs and endpoints are first defined in another class as constants:
 

public static final String YOUR_URL =http://www.yourwebsite.com/;
public static final String REGISTER_URI=mobile_data/push_notifications;
public static final String UNREGISTER_URI=mobile_data_unregister/push_notifications;

@Override
protected void onRegistered(Context arg0, String regId) {
Log.d("onRegistered", regId);
int statusCode = -1;
try {
HttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(Constants.YOUR_URL + Constants.REGISTER_URI);
List nameValuePairs = new ArrayList(2);
nameValuePairs.add(new BasicNameValuePair("token", regId));
nameValuePairs.add(new BasicNameValuePair("type", "android"));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
HttpResponse response = client.execute(httpPost);
StatusLine statusLine = response.getStatusLine();
statusCode = statusLine.getStatusCode();
Log.d("Webgrrls Events user register, statusCode", statusCode + "");
} catch (Exception e) {
Log.d("Webgrrls Events user register, exception", e.toString());
GCMRegistrar.unregister(arg0);
}
}

In our case, "type" fix = android. The push notifications module is able to save even iPhone tokens. So here's the differences.
 
All other methods are customized to develop according to the requirements.
I am currently in email contact with the developer of the GCM module. We are expected to work together to expand the GCM module so that it does not require the push notifications table. Thus, it would be possible only with two modules to control the sending of messages to smartphones. But it may take a while. Nevertheless, we would be delighted if other Drupal developers would participate.
  

Comments

Submitted by tgzbeum (not verified) on
Hello, I have create this class in android for to register
but a have an error

package com.domaine.app; 

import java.util.ArrayList; import java.util.List; 
import org.apache.http.HttpResponse; 
import org.apache.http.StatusLine; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.entity.UrlEncodedFormEntity; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.message.BasicNameValuePair; 
import android.content.Context; 
import android.content.Intent; 
import android.util.Log; 
import com.google.android.gcm.GCMBaseIntentService; 
import com.google.android.gcm.GCMRegistrar; 
 
public class MainActivity extends GCMBaseIntentService { 
 
protected MainActivity(String senderId) { 
  super(senderId); 
  // TODO Auto-generated constructor stub 
public static final String YOUR_URL = "http://app.com/site/"; 
public static final String REGISTER_URI = "mobile_data/push_notifications"; 
public static final String UNREGISTER_URI = "mobile_data_unregister/push_notifications"; 
 
protected void onRegistered(Context arg0, String regId) {
   Log.d("onRegistered", regId); 
   int statusCode = -1; 
   try { 
    HttpClient client = new DefaultHttpClient(); 
    HttpPost httpPost = new HttpPost(YOUR_URL + REGISTER_URI); 
    List nameValuePairs = new ArrayList(2); 
    nameValuePairs.add(new BasicNameValuePair("token", regId)); 
    nameValuePairs.add(new BasicNameValuePair("type", "android")); 
    httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8")); 
    HttpResponse response = client.execute(httpPost); 
    StatusLine statusLine = response.getStatusLine(); 
    statusCode = statusLine.getStatusCode(); 
    Log.d("Webgrrls Events user register, statusCode", statusCode + "");
    } 
    catch (Exception e) { 
      Log.d("Webgrrls Events user register, exception", e.toString()); 
      GCMRegistrar.unregister(arg0); 
    } 
@Override 
protected void onError(Context arg0, String arg1) {
   // TODO Auto-generated method stub 
@Override 
protected void onMessage(Context arg0, Intent arg1) { 
  // TODO Auto-generated method stub 
@Override
protected void onUnregistered(Context arg0, String arg1) {
   // TODO Auto-generated method stub 
 
 
The error 06-26 15:52:58.915: E/AndroidRuntime(16815): 
FATAL EXCEPTION: main 06-26 15:52:58.915: 
E/AndroidRuntime(16815): java.lang.RuntimeException: 
Unable to instantiate activity 
ComponentInfo{
com.peopleinput.pospatisen/com.peopleinput.pospatisen.MainActivity}: 
java.lang.InstantiationException: 
can't instantiate class com.peopleinput.pospatisen.MainActivity; 
no empty constructor 06-26 15:52:58.915: 
E/AndroidRuntime(16815): 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2220) 
06-26 15:52:58.915: E/AndroidRuntime(16815): 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2354)
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at android.app.ActivityThread.access$600(ActivityThread.java:150) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1244) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at android.os.Handler.dispatchMessage(Handler.java:99) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at android.os.Looper.loop(Looper.java:137) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at android.app.ActivityThread.main(ActivityThread.java:5193) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at java.lang.reflect.Method.invokeNative(Native Method) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at java.lang.reflect.Method.invoke(Method.java:511) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(
ZygoteInit.java:795) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at dalvik.system.NativeStart.main(Native Method) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 Caused by: java.lang.InstantiationException: 
 can't instantiate class com.peopleinput.pospatisen.MainActivity; 
 no empty constructor 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at java.lang.Class.newInstanceImpl(Native Method) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at java.lang.Class.newInstance(Class.java:1319) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at android.app.Instrumentation.newActivity(Instrumentation.java:1054) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): 
 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211) 
 06-26 15:52:58.915: E/AndroidRuntime(16815): ... 11 more Thanks to help

Submitted by tgzbeum (not verified) on

Hi android_oma, thanks to help.
finally I see the problem : a mistake in SENDER_ID.

Submitted by juanhernandezes... (not verified) on

Hello android_oma, congratulations for your tutorial! i followed it step by step but i didn´t get it..
I also followed his tutorial https://developers.google.com/eclipse/docs/endpoints-androidconnected-gae and i modified the onRegistered method with your code but nothing happened... in log cat i can see Log.d("onRegistered", regId) with its code and also i can see Log.d("Webgrrls Events user register, statusCode", statusCode + ""); with statuscode = 503 and after that, tag = GCMBaseIntentService , text = Releasing wakelock, but nothing more...
From my drupal site i try to send a message but i get "No Android recipients found, potentially for this language." all the time. I don´t know if i´m doing something wrong and what i must do because I can´t see any device registered from drupal.
one more thing, a stupid question:
I have public static final String REGISTER_URI = "mobile_data/push_notifications"; i suppose that i don´t have to reemplace "mobile_data/push_notifications" with any code, don´t I?
Thanks in advance for your help, if you need any code fragment or what else, tell me please.

android_oma's picture

Hello Juan,
thanks for your question. First of all, if your endpoint was defined as "mobile_data/push_notifications" and you want to use it as constant, than you should not change the code. We have defined our constants into a different package. Might be, you want to go a different way.
Your other question: is it possible, that the following 2 permissions are not enabled in your durpal - site?
Register Device Token    --> Guest (should be enabled)
Remove Device Token   --> Guest (should be enabled)
 

Twitter Username: 
@android_oma

Submitted by juan hernandez (not verified) on

Hi android_oma! thanks for your fast answer, finally i could solve it!
I explain what i did:
First of all i had my drupal site in maintenance mode and that was the reason of statuscode = 503. After changing this parameter i got status code = 401.
I solved this giving permissions to everyone in people/permissions section (scroll down to "Push Notifications", and mark down whichever permissions you want) so in this way i got status code = 200 (everything ok) and I could send a push notification.

Now I´d like to develop my own "code.php" in order to send a push notification to a specific user when someone access to a public page in my site. Could you give me any clue for doing this? I´m a beginner on this and I don´t know if I must use rules, or looking at the code of push notifications module and rewrite it in my code.php, or there is another easier way..

Thanks again for your help, I doubt a lot that I had achieved it without your tutorial.

android_oma's picture

Hi Juan,
that sounds great, that my answer could help you in one part.
The methode, I used to send push notification was by rules. But I had not the requirement to identify one special user for it. Because, the regId is every time anonymous. If you know the regId of this specific user (might be your own regId - will be given via debugging on your own phone or during tests), you could work with rules for it. 

Twitter Username: 
@android_oma

Submitted by juan hernandez (not verified) on

Hi android_oma, thanks for your advise.
Just one more question referring to the unregister.
I can´t access to mobile_data_unregister/push_notifications service from the app, when i try it, i get status code = 400.
if I try:
mobile_data -- > status code = 200
mobile_data_register/push_notifications -- > status code = 200
mobile_data_unregister -- > status code = 200
but with mobile_data_unregister/push_notifications -- > status code = 400.

Users have also permissions to remove Device Token and i do exactly the same than in "onRegister" method but obviously with UNREGISTER_URI constant so i don´t know what can be wrong with the unregister service... Any clue?

Thanks in advance,
Juan.

android_oma's picture

Hello Juan,
I haven't implemented the unregistration. Until now it was not necessary, because there are not so many regIds to unregister. So I send me an email (through a rule) with the deactivated regIds and delete them manual with a sql-statement into the database. In some weeks I will find the way to do it also automatic via android and Drupal. May be some other readers of this article tried it and could leave a comment here. If not, I will post the solution after finding it.

Twitter Username: 
@android_oma

Submitted by Alessandro (not verified) on

Sorry for my english,
have you solved the automatic deletion of inactive token ?

Submitted by tamsir (not verified) on

Hi android_oma
Finally I resolve the problem with 'The controller can not be found'.
Thanks.
Now I try to send notifications with rules but the push notifications (point 3.1.1 in the tutorial) I receive in my phone is empty (no text). I use title=[node:title] in the KEY-VALUE block. Any Ideas?

Submitted by Amine (not verified) on

Hello how did you resolve the problem with "The controller can not be found"?

Twitter Username: 
@ouafiamine

Submitted by android_fifi (not verified) on

Hi, I've followed all the step you stated and I manage to register my device to Drupal as token using sample code Demo activity from android developer training, but when I try to send push notification from drupal, it says

"Successfully sent 0 Android push messages (attempted to send 1 messages)."

why is this happening? I ran out of solution and I've been trying to solve this for days. Please help me.

Submitted by ArenDroid (not verified) on

I am in the same boat: "Successfully sent 0 Android push messages (attempted to send 1 messages)."

Still unsure why this happens. Will report if I find a solution.

Submitted by ArenDroid (not verified) on

The error: "Successfully sent 0 Android push messages (attempted to send 1 messages).", in my case, turned out to be a 401 unauthorized issue as return by the google api. Even though I had whitelisted my ipv4 address, I had not done so for my ipv6 address. Adding this solved the problem at once.

Thanks for this great write up

android_oma's picture

Hello ArenDroid,
thanks for sending the solution of the problem. It will help some other developer.

Twitter Username: 
@android_oma

Submitted by Prasadidasi (not verified) on

I am also getting the error "Successfully sent 0 Android push messages (attempted to send 1 messages). I didn't quite understand ArenDroid's solution; do you mean the ip address for the server? Please explain in detail.

Submitted by Prasadidasi (not verified) on

I have registered my mobile device following the instructions given in this page. I am implementing GCM in an android application and am not able to send push notifications from the Drupal site.
"Successfully sent 0 Android push messages (attempted to send 3 messages)."
Don't know what is wrong and how to resolve it. ArenDroid's solution is not working for me. Can anybody please help?

Submitted by Hans (not verified) on

Hi there,
I followed the whole procedure. Installing modules Services, Push Notifications, GCM. So far, so good. Ending on www.website.com/mobile_data/push_notification this results in a empty white page... no source.
Any ideas? Thanks in advance. Best regards.

android_oma's picture

Hello Hans,
are you sure, that you have set the endpoint in the right way?

Twitter Username: 
@android_oma

Submitted by Girish Kumar Gupta (not verified) on

Hi,
nice tutorial,
can you explain me in detail that how did you enable php code feature to write php code in the text field of gcm module to retrieve all tokens from database table.

android_oma's picture

Hello together,
because of the fact, that so many people have problems with this, I think, the best solution is to upload the complete android-code to Git-Hub. Please be patient, I have actually no account and I haven't worked with Git-Hub. Thatswhy I need help from a colleague to do this. If it is done, I will publish the URL here.

Twitter Username: 
@android_oma

Submitted by sneha (not verified) on

Hi ,
I follow all the steps and same code as your.
I also got a GCM red Id..

But when I m post the url with token and type.
It give 406 Status code .

Please anyone help me to solve this issue.

Submitted by sneha (not verified) on

Hi,

I follow all the steps as tutorial.
My device is successfully register on server by using GCM Id.

My problem is that , from server when sending push notification it shows 'Successfully send notification' , but this notification is not receive on phone.

Can you please suggest me what should I do....

android_oma's picture

Hello Anuj, I am not sure, if I can help, because I don't know your code and other properties. On the last weekend I tried to update Piwik on my Server. Piwik needs php-version 5.3.3 or higher. The installation of the webgrrls-rheinmain-website was under php 5.3.2. After the update, the webgrrls-events-app could not get a connection to the website. After reading some stack-overflow-articles I found out, that the php-version is the reason for the error. The Push Notification Module will not work with it. 
If this information will not help you, so might be, it can help the others.

Twitter Username: 
@android_oma

Add new comment

Bitte geben Sie Ihre E-Mail-Adresse ein. Sie wird nicht angezeigt.
@

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
1 + 0 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.