Mercoledì 23 Gennaio 2019

Android: integrare le notifiche push

Creato il: 18 novembre 2013

[EDIT: NUOVO ARTICOLO AGGIORNATO: Android: notifiche push, aggiornamento 2/2014]

Non ho mai trovato un tutorial o un articolo esauriente che spieghi l’implementazione delle notifiche push in Android: sempre domande senza risposta, guide che non portano a nulla… ma oggi ne ho trovata una (piena di extra e in inglese) che mi ha aiutato nell’impresa!
Ho quindi deciso di scrivere io un tutorial in italiano su come implementare le notifiche push in android.
Non sono molto bravo a spiegarmi e a scrivere 🙂 ma spero che capiate, nel caso basta un commento e cercherò di aiutarvi!

Ricordiamoci, che il servizio push di Google si chiama Google Cloud Messaging (GCM), e non Android Cloud to Device Messaging Framework (C2DM), che è ora obsoleto.

gcm-logo

Prima di partire, un doveroso ringraziamento va al mio collega Simone Cabrino (http://simone.cabrino.it/) per la parte server, e a Ravi Tamada (http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/) autore dell’articolo in inglese.

Prepariamo il cervello alla procedura:

  • Lo smartphone comunicherà a Google l’iscrizione al servizio di notifiche della nostra app
  • Google gli risponderà con un ID univoco, che lo smartphone girerà al nostro server LAMP
  • Il server comunicherà a Google l’invio di notifiche agli smartphone collegati
  • Google invierà le notifiche

questo il succo della guida.

1) Preparare Google
andate nella pagina delle api di Google loggandovi con il vostro account google sviluppatore
create un nuovo progetto, e tenete da conto il codice che vedrete nell’url (una cosa simile a https://code.google.com/apis/console/#project:460866929976), dopo i :, sarà il vostro project_id
cliccate su services e abilitate Google Cloud Messaging for Android
cliccate su API Access e segnatevi la API key sotto a Key for browser apps (with referer)

3) Preparare l’app
andate in eclipse e dentro all’Android SDK manager: tra gli extra troverete la google cloud Messaging da scaricare, fatelo e cercatelo nel vostro computer sotto a vostro_android_sdk_foder\extras\google\gcm\gcm-client\dist, troverete un file gcm.jar da copiare nella cartella della vostra app (io l’ho copiato li e poi l’ho collegato tramite eclipse e il java build path
preparate un emulatore google api in eclipse (e attivate un utente gmail nei suoi account) o collegate il vostro cell (se come me avete la fortuna che ve lo riconosca)

4) Modificare il codice dell’app
Premessa: tutto quello che trovate nel codice come it.dferrari.notifiche dovrà essere modificato per adattarlo a voi, del tipo namespace.nome_app
aprite il vostro AndroidManifest, e modificatelo come segue:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="it.dferrari.notifiche" android:versionCode="1" android:versionName="1.0">
    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="10" />
    <permission android:name="it.dferrari.notifiche.permission.C2D_MESSAGE" android:protectionLevel="signature" />
	<uses-permission android:name="it.dferrari.notifiche.permission.C2D_MESSAGE" /> 
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
	<uses-permission android:name="android.permission.WAKE_LOCK" />
	<uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.INTERNET" />
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" />
	<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar" android:allowBackup="false">
		<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
			<intent-filter>
				<action android:name="com.google.android.c2dm.intent.RECEIVE" />
				<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
				<category android:name="it.dferrari.notifiche" />
			</intent-filter>
		</receiver>
		<service android:name=".GCMIntentService" />
	    <activity android:name="Index" android:label="@string/app_name" android:screenOrientation="portrait" android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
	</application>
</manifest>

tutte le user-permission sono da inserire poiché obbligatorie, il receiver e il service anche. Come vedete, ho una sola activity (perché è giusto un’app di esempio), activity chiamata Index e che contiene il codice che volete voi, chiaramente andrà modificato dopo per integrare le notifiche, ma per il resto è vostra scelta: insomma non è una classe dedicata.
—————————————————————–
creiamo nel nostro progetto la classe CommonUtilities, che conterrà

package it.dferrari.notifiche;

import android.content.Context;
import android.content.Intent;
 
public final class CommonUtilities {
    // indirizzo del server per registrare
    static final String SERVER_URL = "http://www.d-ferrari.it/register.php"; 
    // ID del progetto di google
    static final String SENDER_ID = "1111111111"; 
    static final String TAG = "Notifica per android";
    static final String DISPLAY_MESSAGE_ACTION = "it.dferrari.notifiche.DISPLAY_MESSAGE";
    static final String EXTRA_MESSAGE = "message";
    static void displayMessage(Context context, String message) {
        Intent intent = new Intent(DISPLAY_MESSAGE_ACTION);
        intent.putExtra(EXTRA_MESSAGE, message);
        context.sendBroadcast(intent);
    }
}

questa classe imposta dei parametri quali SERVER_URL e SENDER_ID che dovrete cambiare con il vostro indirizzo della pagina register.php (che vedremo al punto 5) e con il vostro id di progetto google (visto al punto 1)
—————————————————————–
creiamo nel nostro progetto la classe ServerUtilities, che conterrà

package it.dferrari.notifiche;

import static it.dferrari.notifiche.CommonUtilities.SERVER_URL;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import android.content.Context;
import com.google.android.gcm.GCMRegistrar;
 
public final class ServerUtilities {
    private static final int MAX_ATTEMPTS = 5;
    private static final int BACKOFF_MILLI_SECONDS = 2000;
    private static final Random random = new Random();
    static void register(final Context context, final String regId) {
        String serverUrl = SERVER_URL;
        Map<String, String> params = new HashMap<String, String>();
        params.put("regId", regId);
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {
            try {
                post(serverUrl, params);
                GCMRegistrar.setRegisteredOnServer(context, true);
                return;
            } catch (IOException e) {
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    Thread.currentThread().interrupt();
                    return;
                }
                backoff *= 2;
            }
        }
    }
    static void unregister(final Context context, final String regId) {
        String serverUrl = SERVER_URL + "/unregister";
        Map<String, String> params = new HashMap<String, String>();
        params.put("regId", regId);
        try {
            post(serverUrl, params);
            GCMRegistrar.setRegisteredOnServer(context, false);
        } catch (IOException e) {
        }
    }
    private static void post(String endpoint, Map<String, String> params) throws IOException {
        URL url;
        try {
            url = new URL(endpoint);
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("invalid url: " + endpoint);
        }
        StringBuilder bodyBuilder = new StringBuilder();
        Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
        while (iterator.hasNext()) {
            Entry<String, String> param = iterator.next();
            bodyBuilder.append(param.getKey()).append('=').append(param.getValue());
            if (iterator.hasNext()) {
                bodyBuilder.append('&');
            }
        }
        String body = bodyBuilder.toString();
        byte[] bytes = body.getBytes();
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setFixedLengthStreamingMode(bytes.length);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
            OutputStream out = conn.getOutputStream();
            out.write(bytes);
            out.close();
            int status = conn.getResponseCode();
            if (status != 200) {
              throw new IOException("Errore " + status);
            }
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
      }
}

questa è la classe che fornisce i metodi per la comunicazione app-server, contiene infatti metodi di registrazione, cancellazione, post, …
Ricordiamoci infatti, che uno smartphone si deve registrare al servizio, prima di poter ricevere le notifiche.
—————————————————————–
creiamo nel nostro progetto la classe WakeLocker, che conterrà

package it.dferrari.notifiche;

import android.content.Context;
import android.os.PowerManager;
 
public abstract class WakeLocker {
    private static PowerManager.WakeLock wakeLock;
 
    public static void acquire(Context context) {
        if (wakeLock != null) wakeLock.release();
 
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
                PowerManager.ACQUIRE_CAUSES_WAKEUP |
                PowerManager.ON_AFTER_RELEASE, "WakeLock");
        wakeLock.acquire();
    }
 
    public static void release() {
        if (wakeLock != null) wakeLock.release(); wakeLock = null;
    }
}

questa classe ha poche spiegazioni, si occupa semplicemente di svegliare il telefono dallo stand-by quando una notifica arriva.
—————————————————————–
creiamo nel nostro progetto la classe GCMIntentService, che conterrà

package it.dferrari.notifiche;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;

import com.google.android.gcm.GCMBaseIntentService;
import static it.dferrari.notifiche.CommonUtilities.SENDER_ID;
import static it.dferrari.notifiche.CommonUtilities.displayMessage;
 
public class GCMIntentService extends GCMBaseIntentService {
    public GCMIntentService() {
        super(SENDER_ID);
    }
    @Override
    protected void onRegistered(Context context, String registrationId){
        ServerUtilities.register(context, registrationId);
    }
    @Override
    protected void onUnregistered(Context context, String registrationId){
        ServerUtilities.unregister(context, registrationId);
    }
    @Override
    protected void onMessage(Context context, Intent intent) {
        String message = intent.getExtras().getString("price");
        displayMessage(context, message);
        generateNotification(context, message);
    }
    @Override
    protected void onDeletedMessages(Context context, int total) {
    }
    @Override
    public void onError(Context context, String errorId) {
    }
    @Override
    protected boolean onRecoverableError(Context context, String errorId) {
        return super.onRecoverableError(context, errorId);
    }
    private static void generateNotification(Context context, String message) {
        int icon = R.drawable.ic_launcher;
        long when = System.currentTimeMillis();
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        Notification notification = new Notification(icon, message, when);
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        String title = context.getString(R.string.app_name);
        Intent notificationIntent = new Intent(context,classe_che_volete.class);
		notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
		PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
		notification.setLatestEventInfo(context, title, message, intent);
		notification.flags |= Notification.FLAG_AUTO_CANCEL;
		notification.defaults |= Notification.DEFAULT_SOUND;
		notificationManager.notify(0, notification);
    }
}

questa classe rappresenta il vero hook della notifica che arriverà al telefono: ora, io ho deciso di sparare un intent quando mi arriva la notifica e la clicco dalla notification bar, ma ognuno può fare quello che vuole.
Se vi va bene un intent, modificate semplicemente classe_che_volete.class con la vostra classe, altrimenti dovrete agire sul codice da dopo di String title a prima di notification.setLatestEventInfo.
Voglio far presente che questa classe DEVE risiedere nel main package della vostra app, quindi se il vostro package è it.voi.app, il file va li e non in it.voi.app.utils (che magari avete creato, dipende dalla programmazione di ognuno).
—————————————————————–
modifichiamo la classe Index

package it.dferrari.notifiche;

import com.google.android.gcm.GCMRegistrar;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.Toast;
import static it.dferrari.notifiche.CommonUtilities.DISPLAY_MESSAGE_ACTION;
import static it.dferrari.notifiche.CommonUtilities.EXTRA_MESSAGE;
import static it.dferrari.notifiche.CommonUtilities.SENDER_ID;

public class Index extends Activity {
	ProgressDialog progressBar;
    AsyncTask<Void, Void, Void> mRegisterTask;
	String regId="";
    GoogleCloudMessaging gcm;
	Context context;
    @Override
	public void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.index);
		context = this;
        // Il telefono risulta pronto
        GCMRegistrar.checkDevice(this);
        // Il manifesto risulta pronto
        GCMRegistrar.checkManifest(this);
        registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
        // Ottieni il Registration ID
        regId = GCMRegistrar.getRegistrationId(this);
        // Controllo se sono registrato
        if (regId.equals("")) {
            // Mi registro
            new registra_background().execute();
        } else {
            // Sono registrato
            if (!GCMRegistrar.isRegisteredOnServer(this)) {
                // Provo a registrarmi ancora
                mRegisterTask = new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        ServerUtilities.register(context, regId);
                        return null;
                    }
                    @Override
                    protected void onPostExecute(Void result) {
                        mRegisterTask = null;
                    }
                };
                mRegisterTask.execute(null, null, null);
            }
        }
		// vostro codice personale
	}
    /**
     * Ricevo notifica push
     * */
    private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
            // Sveglia il telefono se è in stand-by
            WakeLocker.acquire(getApplicationContext());
            // Visualizza il messaggio
            Toast.makeText(getApplicationContext(), "New Message: " + newMessage, Toast.LENGTH_LONG).show();
            // Rilascia il wavelocker
            WakeLocker.release();
        }
    };
    @Override
    protected void onDestroy() {
        if (mRegisterTask != null) {
            mRegisterTask.cancel(true);
        }
        try {
            unregisterReceiver(mHandleMessageReceiver);
            GCMRegistrar.onDestroy(this);
        } catch (Exception e) {
        }
        super.onDestroy();
    }
    private class registra_background extends AsyncTask<Void, Integer, Void> {
        int progress_status;
        @Override
        protected void onPreExecute(){
            super.onPreExecute();
        }
        @Override
        protected Void doInBackground(Void... params){
            try{
                if (gcm == null) {
                    gcm = GoogleCloudMessaging.getInstance(context);
                }
                regId = gcm.register(SENDER_ID);
                Log.e("TOKEN",regId);
            }catch(Exception ex){
                System.out.println("Errore dati");
            }
            return null;
        }
        @Override
        protected void onProgressUpdate(Integer... values){
        }
        @Override
        protected void onPostExecute(Void result){
            mRegisterTask = new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    ServerUtilities.register(context, regId);
                    return null;
                }
                @Override
                protected void onPostExecute(Void result) {
                    mRegisterTask = null;
                }
            };
            mRegisterTask.execute(null, null, null);
        }
    }
}

dove leggete // vostro codice personale è la zona dove potete scrivere il vostro codice personale, dell’onCreate(). il resto, è l’aggiunta alla classe: in pratica, controlliamo che il telefono sia registrato e in caso negativo lo registriamo al server per portarci a casa (e dare al server) il regId del telefono (molto importante in quanto google lo userò per farci arrivare la notifica).

5) La parte server
Questa parte consiste in due file e poche righe di codice ma precise: il file push.php e il file register.php, inoltre conterrà la parte SQL che dovrete integrare.
Tutte le volte che vedrete vostro_db,vostro_user,vostra_password dovrete modificare per inserire i vostri dati mysql
il database:
create una tabella chiamata android_udid, che conterrà il campo id come int(100) e primary_key autoincrement, e il campo registration_id che sarà un varchar(256) not null.
—————————————————————–
il file register.php

<?php // database
define("DB_NAME","vostro_db");
define("DB_USER","vostro_user");
define("DB_PASSWORD","vostra_password");
define("DB_HOST","localhost");
define("DB_CHARSET","utf8");
$mysqli=new mysqli(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME);
if($mysqli->connect_errno){
	echo "Failed to connect to MySQL:(".$mysqli->connect_errno.") ".$mysqli->connect_error;
}
$registration_id=isset($_POST["regId"]) ? $_POST["regId"] : "";
$registration_id=$mysqli->real_escape_string($registration_id);
if($registration_id!=""){
	$res=$mysqli->query(sprintf("SELECT * FROM android_udid WHERE registration_id='%s'",$registration_id));
	if($res->num_rows==0){
		$mysqli->query(sprintf("INSERT INTO android_udid(registration_id) VALUES('%s')",$registration_id));
	}
} ?>

questo è il file che si occupa della registrazione, il file che dovrete richiamare nella classe CommonUtilities come vi ho scritto.
Compilate i campi inerenti il database con le vostre credenziali.
Controlla che il regId non sia già presente, e in caso positivo lo aggiunge registrando così lo smartphone.
—————————————————————–
il file push.php

<?php // errori
ini_set("display_errors",1);
ini_set("display_errors",1);
// database
define("DB_NAME","vostro_db");
define("DB_USER","vostro_user");
define("DB_PASSWORD","vostra_password");
define("DB_HOST","localhost");
define("DB_CHARSET","utf8");
$mysqli=new mysqli(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME);
if($mysqli->connect_errno){
	echo "Failed to connect to MySQL:(".$mysqli->connect_errno.") ".$mysqli->connect_error;
}
class GCM{
    function __construct(){}
    public function send_notification($registatoin_ids,$message){
        // GOOGLE API KEY
		define("GOOGLE_API_KEY","vostra_api_key");
        $url="https://android.googleapis.com/gcm/send";
        $fields=array(
            "registration_ids"=>$registatoin_ids,
            "data"=>$message,
        );
		var_dump($fields);
        $headers=array(
            "Authorization: key=".GOOGLE_API_KEY,
            "Content-Type: application/json"
        );
        $ch=curl_init();
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_POST,true);
        curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ch,CURLOPT_POSTFIELDS,json_encode($fields));
        $result=curl_exec($ch);
        if($result===FALSE){
            die("Curl failed: ".curl_error($ch));
        }
        curl_close($ch);
        echo $result;
    }
}
// ======================
//=INVIA LE NOTIFICHE AGLI UTENTI =
// ======================
$messaggio="Ciao, sono una notifica!";
$pushCounter=0;
$registatoin_ids=array();
$result2=$mysqli->query("SELECT * FROM android_udid");
while($obj2=$result2->fetch_object()){
	$token=$obj2->registration_id;
	if($token!=""){
		$registatoin_ids[]=$token;
		$pushCounter++;
	}
}
if($pushCounter>0){
	$gcm=new GCM();
	$message=array("price"=>$messaggio);
	$result_android=$gcm->send_notification($registatoin_ids,$message);
	echo $result_android;
}

questa è la pagina che si preoccupa di inviare la notifica agli utenti iscritti (e che hanno il regId salvato nel vostro db): quando la eseguirete, le notifiche arriveranno agli smartphone iscritti. E’ chiaramente modificabile per pescare le notifiche da un db, e per fare tutti i lavori che volete su controlli di invio, prevenzione da duplicati di invio tramite date di aggiornamento, …

6) Bene, abbiamo finito!
Ora possiamo provare il funzionamento, e una volta sicuri pubblicare l’app.
Installate l’app da eclipse sul vostro emulatore o sul vostro smartphone, dopodichè navigate fino alla classe Index (per me essendo la prima classe, basta avviare l’app).
Una volta fatto, se non dà errori, controllate nel db tramite phpmyadmin che il vostro telefono sia presente (e sopratutto che l’id sia salvato).
Se tutto è positivo, eseguite push.php e vedrete la notifica arrivare, che cliccata eseguirà l’azione scelta.

Buona programmazione!

  • shine

    Da quello che ho capito, l’invio delle notifiche è verso tutti i smartphone che sono iscritti al servizio, nel caso io sono interessato all’invio della notifica solo ad un determinato smartphone come potrei fare?

    • Beh a meno che tu non salvi altri dati (tipo di telefono, sistema operativo, …) in un database per fare la parte server selettiva, non puii

    • Orphen

      Salve Dott. Ferrari,
      devo ammettere che ancora non ho provato l’App, poichè devo implementare il server in java , usando le api jersey, per fare un server restfull. quindi prima di iniziare a scrivere volevo capire una cosa.
      lei dice:
      [quote]
      5) La parte server
      Questa parte consiste in due file e poche righe di codice ma precise: il file push.php e il file register.php, inoltre conterrà la parte SQL che dovrete integrare.
      Tutte le volte che vedrete vostro_db,vostro_user,vostra_password dovrete modificare per inserire i vostri dati mysql
      – il database:
      create una tabella chiamata android_udid, che conterrà il campo id come int(100) e primary_key autoincrement, e il campo registration_id che sarà un varchar(256) not null.
      [/quote]

      Non riesco a capire come fa a salvare la id di registrazione di GCM in un varchar(256). Poiché leggendo altre guide tutti dicono che l’ID di registrazione di GCM e una string di bene 4096 caratteri.
      Potrebbe spiegarmi come fa?
      Grazie.
      By orphen

      • Buongiorno a lei, semplicemente quello che ha letto non è vero. Un id di registrazione gcm è di circa 160 caratteri. si parla in giro di 4k ma è legato allo spazio occupato fisico in kb che PUO’ occupare (ma non che deve), non ad uno spazio database.
        si fidi e vada tranquillo con il varchar come ho scritto.

      • Orphen

        la ringrazio dell’informazione…. ora vedo di scrivere anche il server in java, che una volta scritto se sara funzionante le invierò il codice. se vorrà, potrà aggiungerlo all’articolo, per le persone che avranno, lo stesso mio problema.

  • ciao Davide grazie per il tutorial

    Vorrei porti una domanda. come posso evitare che il display si illumini quando arriva una notifica, vorrei che restasse nello stato in cui si trova nel momento dell’evento.
    grazie
    Marco

    • devi guardare il metodo
      private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
      è lui che attiva il wakelocker e mostra il messaggio

  • drucks87

    Ciao a tutti,
    ogni quanto google modifica l’id del telefono registrato?

    • 😐
      l’id è id del telefono univoco (come un IMEI per esempio), non si modifica mai.
      qualcuno ti cambierebbe il codice fiscale?

  • Francesco

    Ho seguito il tuo tutorial, ho provato ieri sera, subito dopo aver installato l’app, e funzionava. Riprovato stamattina… “key expired”. Ho disinstallato e reinstallato l’app e ha subito funzionato. Come faccio a risolvere questo problema? Grazie

    • Quasi sicuramente stai facendo sia un register che un unregister nella tua app, quindi è ovvio che la key sia scaduta.

      • Francesco

        scusa in che senso? potresti spiegarmi meglio ?

      • tu in qualche modo e in qualche momento chiami la funzione static void unregister della classe ServerUtilities.

      • Francesco

        nel mainactivity faccio: protected void onPause() {
        super.onPause();
        GCMRegistrar.unregister(this);
        }

        e in GCMIntentService faccio: @Override
        protected void onUnregistered(Context arg0, String arg1) {
        Log.i(TAG, “unregistered = “+arg1);

        }

        quali dei due devo togliere?

      • Ovviamente il primo, perché stai dicendo: quando l’activity va in pausa cancella l’utente.
        Il secondo è un semplice log di sistema che non serve a niente.

  • mic

    grazie adesso controllo la mia mail. Allora tu pensi che il problema potrebbe essere come ho creato il db??provo con easyphp allora..

  • mic

    grazie allora adesso sono riuscito a farmi tornare true, provando con:
    http://10.0.0.2/register.php
    però non risulta nessun record nel db(con xampp)
    Nel logcat non riesco a capire dove ho il problema, cioè non riesco a capire se il problema è nella creazione del db . Mi consigli di usare sempre xampp o provare con un altro web server?grazie tante sei gentilissimo

    • io ho sempre usato easyphp, che ha sempre fatto il suo dovere. cmq se nel db non ci sono record, credo che il logcat non centri. inoltre la tua mail viene segnata come spam da phishing, ocio: spero sia solo per via di un indirizzo ip nella mail

  • mic

    ciao e complimenti, io uso xampp, ho implementato tutto, ma non riesco a registrarmi al server, visto che xampp è in locale qual’è il serverURL corretto?

    http://localhost/register.php???o altro
    perchè nel logCat mi ritorna:
    Is registered on server: false

    • non ne ho la minima idea, ma una cosa è sicura: il localhost

  • Domenico

    Salve io ho progettato un app con “App inventor” c’è il modo di integrare questa funzione?

    • Salve, non so bene perché io non uso programmi come app inventor o titanium, in quanto figli del demonio per uno sviluppatore.
      Ma onestamente ti risponderei di no, perché ho appena letto che questi software non generano sorgenti Java: ci sarà un modo diverso da questo sicuramente.

      • Domenico

        Ok, ma il sistema funziona solo se inserisco la stringa di codice sul manifest?

      • ? quella parte, del manifest, è solo una piccola parte del tutto, non basta solo lei

  • Luigi

    Complimenti, ottimo tutorial, molto più diretto della documentazione ufficiale 🙂

    • merito forse della mia poca capacità di scrivere 🙂 o forse della mia voglia di fare le cose semplici e in italiano 🙂

  • Pingback: Android: notifiche push, aggiornamento 2/2014 | Davide Ferrari()

  • Giancarlo

    Ciao,
    volevo chiedere un aiuto in quanto da oggi quando tento di inviare le notifiche alla pubblicazione di un nuovo articolo nel blog mi ritrovo con questo errore (lo riporto per intero):

    [Edit]

    Non capisco dove sia l’errore. L’invio delle notifiche ha sempre funzionato senza problemi!

    Grazie

    • Tralasciando che potevi evitare un commento così lungo e pieno di id di smartphones, perché ora io o chiunque altro sul web possiamo combinare casini che neanche immagini per colpa tua, il tuo problema è che alla riga indicata hai fatto un echo o un die o un var_dump… E quindi hai già dato qualcosa da esporre al browser.

      • Giancarlo

        Ok ti ringrazio.
        L’ho scritto perchè semplicemente credevo ti servisse tutto per capire che tipo di errore fosse…comunque ti autorizzo ad eliminare il mio commento.
        Comunque grazie. Proverò a ri-controllare il codice.

  • Marco

    Guida utilissima! Funziona perfettamente…Avrei una domanda, come faccio a far comparire, invece di una notifica a tempo, un message box che si deve chiudere manualmente (ad esempio con la classica x in alto a destra)???

  • Alessandro

    Ciao, non mi sono ancora “sporcato le mani” con il codice 😉 , ma ti faccio subito una domanda: anche nel tuo Android SDK manager, la voce “Google Cloud Messaging for android” e’ marcata come “[Deprecated]” ?

    • Ciao, no da me non è deprecated

    • Ivan

      si anche a me.. infatti GCMRegistrar mi va in errore
      che faccio la scarico? ma poi funge?

  • Giancarlo

    Un saluto a tutti!
    Io vorrei dare la possibilità all’untente di scegliere se ricevere o meno le notifiche push. Ho creato la relativa preferenceActivity con il relativo checkbox. Però ho un dubbio : su quale classe dovrei richiamare le preferenze? sulla classe index non funziona in quanto si che attivi o meno le notifiche, quest’ultime arrivano ugualmente..

  • Gianfranco

    Buongiorno Dott. Ferrari,

    non so se ha avuto modo e tempo di leggere la mail che Le ho inviato ieri.
    Per essere più chiaro mi servirebbe un aiuto o un consiglio su come implementare la funzionalità “Push Video” su una IP Camera che non ha nativamente quella preziosa funzionalità .
    Può dare una occhiata alle specifiche nel seguente manuale utente:
    https://www.dropbox.com/s/baf82hf2b4ieml5/B%20Series%20User%20Manual%28Astro%20Boy%29.doc

    Probabilmente si può sfruttare la funzionalità “Alarm Server” che altrimenti non si capisce a cosa serve e come potrebbe essere utilizzata.

    Mi farebbe un gran favore se mi potesse dare un aiuto, un suo parere o qualche suggerimento utile.

    La ringrazio anticipatamente per la sua cortesia e chiedo scusa del disturbo.

    • Buongiorno, ho letto la sua mail ma le devo dire che non è proprio la mia competenza, è uscito dalle mie conoscenze

  • M&M

    Ciao Grazie per il tutorial, volevo chiedere perché non riesco ad importare questi due elementi…
    import com.google.android.gms.common.GooglePlayServicesUtil;
    import com.google.android.gms.gcm.GoogleCloudMessaging;
    è come se non avessi le librerie…. mentre
    import com.google.android.gcm.GCMRegistrar;
    lo riesco ad importare, questi import fanno parte della stessa libreria gcm?

    • ti chiederei di controllare se hai le librerie a posto nel java buold path, in particolare google-play-service_lib e gcm.jar, in particolare se siano attive (sottomenu order export)

  • Paolo

    Ciao grazie mille per il tutorial, per caso puoi indirizzarmi ad un esempio Java dello stesso Server Side piuttosto che Php? Grazie mille! 🙂

  • Pingback: Modifica importante all’articolo sulle notifiche push di Android | Davide Ferrari()

  • Mary

    Ho qualche dubbio in merito alla registrazione. Quando avvio per la prima volta l’app procedo con la registrazione del device al servizio gcm, successivamente non serve più registrarsi. L’annullamento della registrazione serve nel momento in cui l’utente non vuole più ricevere le notifiche, giusto?
    A parte ciò, ho problemi durante l’esecuzione della mia app. In particolare quando esco dall’app, ho un errore sull’activity causato da “missing a call to unregister receiver”. Suggerimenti di come risolvere il problema?

  • Francesco

    Ciao,
    Complimenti e grazie per i tuoi preziosi consigli.
    Avrei bisogno di un aiuto ulteriore da parte tua. Nel caso in cui l’applicazione è in foreground vorrei che all’arrivo della notifica non mi comparisse la notifica ma direttamente il messaggio in una TextView. In attesa di una tua risposta ti ringrazio anticipatamente.
    Ciao

  • Ivan

    Ciao, sono riuscito in pochissimo a far funzionare tutto. Per chi mastica un poco di php e programma Android risulta abbastanza semplice 🙂
    Ho una domanda.. Il testo della mia notifica è relativamente lungo, vorrei quindi visualizzarlo nell’Activity dove “sparo” l’utente, perchè sennò non viene visualizzato tutto. Come faccio a prendere il testo della notifica e “salvarlo” in una variabile?

    Grazie aspetto impazienta la tua risposta

    • Ciao, vedi quella funzione generateNotification() nel file GCMIntentService?
      alla riga dopo Intent notificationIntent… aggiungi una riga con notificationIntent.putExtra(“messaggio”,message);
      e poi nell’activity dove arrivi fai Intent intent = getIntent(); String message = intent.getStringExtra(“messaggio”);

      • Ivan

        Grazie, era più facile del previsto, bastava un semplice putextra.. avevo letto online di ricevere la “mainKey”, ma inutile dire che non fungeva. Dava null, ma così è perfetto, grazie, ottimo tutorial!

        P.S.
        Se facessi altri tutorial di roba come questa o più avanzata, per Android, sarei il primo a seguirti spesso ^^

      • Ah beh, quando posso li faccio 😉 devo anche modificare questo per fare la chiamata di registrazione asincrona, che è piuttosto importante.

      • Ivan

        Problemi con i vecchi device?

        P.S.
        Ho notato che per mandare due notifiche con messaggio diverso sono tenuto ad aspettare un tot di tempo, però il problema si pone solo quando cliccando sulla push mi apre l’intent con la textView, mentre nella push stessa e nel toast visualizza bene la nuova notifica.. spero di essermi spiegato bene.. se è effettivamente così, di quanto tempo si tratta?
        Altrimenti come faccio a mandare due notifiche diverse anche a brevi intervalli di tempo?

      • Ivan

        Mi correggo, non c’entra niente il fattore tempo.. Forse ha a che fare con l’activity che rimane aperta e quindi non mando il nuovo messaggio, quindi non cambia nemmeno la textView.. Come risolvo? :S

  • Alex

    Ciao, complimenti! Come mai una volta arrivata la notifica, cliccandoci sopra sparisce il contenuto del messaggio e visualizza un’attività vuota?

    • Ciao e grazie!
      Se guardi in fondo alla classe GCMIntentService, c’è l’azione da intraprendere per il click della notifica… secondo me hai sbagliato li 🙂

      • Alex

        Ho controllato, è identico! 🙁 Il problema è che quando clicco sulla notifica nella status bar, si apre l’app ma non visualizza il messaggio, ma solo schermo bianco. Cosa potrebbe essere?
        Grazie mille per la tua disponibilità 🙂

      • Se è identico vuol dire che hai lasciato classe_che_volete.class? 😀
        A parte gli scherzi, se è identico deve andare… controlla il receiver nel manifest (prima cosa) e i vari files… altro non so dirti!

      • Alex

        E’ tutto ok… ovviamente non si chiama così 😀 la classe si chiama MainActivity, sembra sia li il problema, smanettando un po’ sono riuscito, una volta premuta la notifica, a far apparire nella schermata bianca una scritta di queste: “android.widget.TextView@4604f850”.

        La MainActivity è questa qui:
        public class MainActivity extends Activity {
        // label to display gcm messages
        TextView lblMessage;
        TextView newMessage;
        // Asyntask
        AsyncTask mRegisterTask;

        // Alert dialog manager
        AlertDialogManager alert = new AlertDialogManager();

        // Connection detector
        ConnectionDetector cd;

        public static String name;
        public static String email;

        @Override
        public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        cd = new ConnectionDetector(getApplicationContext());

        // Check if Internet present
        if (!cd.isConnectingToInternet()) {
        // Internet Connection is not present
        alert.showAlertDialog(MainActivity.this,
        “Internet Connection Error”,
        “Please connect to working Internet connection”, false);
        // stop executing code by return
        return;
        }

        // Getting name, email from intent
        Intent i = getIntent();

        name = i.getStringExtra(“name”);
        email = i.getStringExtra(“email”);

        // Make sure the device has the proper dependencies.
        GCMRegistrar.checkDevice(this);

        // Make sure the manifest was properly set – comment out this line
        // while developing the app, then uncomment it when it’s ready.
        GCMRegistrar.checkManifest(this);

        lblMessage = (TextView) findViewById(R.id.lblMessage);
        newMessage = lblMessage;

        registerReceiver(mHandleMessageReceiver, new IntentFilter(
        DISPLAY_MESSAGE_ACTION));

        // Get GCM registration id
        final String regId = GCMRegistrar.getRegistrationId(this);

        // Check if regid already presents
        if (regId.equals(“”)) {
        // Registration is not present, register now with GCM
        GCMRegistrar.register(this, SENDER_ID);
        } else {
        // Device is already registered on GCM
        if (GCMRegistrar.isRegisteredOnServer(this)) {
        // Skips registration.
        Toast.makeText(getApplicationContext(), “Already registered with GCM”, Toast.LENGTH_LONG).show();
        lblMessage.append(newMessage + “\n”);
        } else {
        // Try to register again, but not in the UI thread.
        // It’s also necessary to cancel the thread onDestroy(),
        // hence the use of AsyncTask instead of a raw thread.
        final Context context = this;
        mRegisterTask = new AsyncTask() {

        @Override
        protected Void doInBackground(Void… params) {
        // Register on our server
        // On server creates a new user
        ServerUtilities.register(context, name, email, regId);
        return null;
        }

        @Override
        protected void onPostExecute(Void result) {
        mRegisterTask = null;
        }

        };
        mRegisterTask.execute(null, null, null);
        }
        }
        }

        /**
        * Receiving push messages
        * */
        private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
        String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
        // Waking up mobile if it is sleeping
        WakeLocker.acquire(getApplicationContext());

        /**
        * Take appropriate action on this message
        * depending upon your app requirement
        * For now i am just displaying it on the screen
        * */

        // Showing received message
        lblMessage.append(newMessage + “\n”);
        Toast.makeText(getApplicationContext(), “New Message: ” + newMessage, Toast.LENGTH_LONG).show();

        // Releasing wake lock
        WakeLocker.release();

        }
        };

        @Override
        protected void onDestroy() {
        if (mRegisterTask != null) {
        mRegisterTask.cancel(true);
        }
        try {
        unregisterReceiver(mHandleMessageReceiver);
        GCMRegistrar.onDestroy(this);
        } catch (Exception e) {
        Log.e(“UnRegister Receiver Error”, “> ” + e.getMessage());
        }
        super.onDestroy();
        }

        }

      • Quella scritta appare perché in zone come Toast.makeText(getApplicationContext(), “New Message: ” + newMessage, Toast.LENGTH_LONG).show(); fai scrivere newMessage che è la textview, non il suo contenuto: devi scrivere newMessage.getText().toString() per vedere il contenuto di una TextView

      • Alex

        Ma newMessage è di tipo stringa e il .getText è non definito per il tipo Stringa :/

      • Vedendo velocemente il tuo codice (sono a lavoro, abbi pazienza), ho intuito che quella fosse una textview.
        Sta di fatto che quella stringa che ti stampa appare perché stai esponendo a schermo la textview senza il getText().toString(), ovunque essa sia

      • Alex

        Purtroppo sto provando e riprovando ma nulla, non riesco. Grazie lo stesso per il tempo che mi hai dedicato, complimenti e scusa il disturbo 🙂

  • Samuele

    Ciao volevo ringraziarti per il tutorial … semplice e completo … l’unico problema serio che ho riscontrato è che non arrivano le notifiche sul dispositivo, chiamando la pagina push.php mi dice:

    array(2) {
    [“registration_ids”]=>
    array(2) {
    [0]=>
    string(162) “APA91bGZHHhAFEv_qg2dOtLl2nPpZq8ZAXwIoHIj2pIzoiAKQH-n7Y5uxLgyEmhbU1lfsFBQiuFE6llUUmgXj1_i-0hp2F2rx7erv5itLQaaUdd2S2ADGrp5EgqLJXfDQN3y2Lc_qoURNukf70x5wjX08D6NcapnEg”
    [1]=>
    string(162) “APA91bGpT9S7qkMQVw5GEmRTS7zBLmYxyckmZzo2-9j65IhStazI4t8vywHU3rN0ew2eEiV2tJiMpeJJ8BBv0J_Q_cCVa2KF7ZH_5CLbLeZ9qKurKQhVM2HDbdONgsiDjM-9-4MX5dMysSsDVRVrMUq6lsyTTWJLjg”
    }
    [“data”]=>
    array(1) {
    [“price”]=>
    string(24) “Ciao, sono una notifica!”
    }
    }
    {“multicast_id”:6372717902480207549,”success”:2,”failure”:0,”canonical_ids”:0,”results”:[{“message_id”:”0:1379951252093719%d152cd3df9fd7ecd”},{“message_id”:”0:1379951252094686%d152cd3df9fd7ecd”}]}

    come dovrei fare??? hai qualche idea??? ho controllato e ricontrollato le chiavi e sono messe come hai descritto …

    altra cosa vedendo il LogCat vedo che in fase di registrazione ricevo ho il seguente errore
    09-23 15:49:46.646: E/GCMRegistrar(1766): internal error: retry receiver class not set yet
    come posso risolvere???

    grazie ancora

  • Valerio

    Ciao, grazie mille per la guida.
    Da qualche mese sto utilizzando la tua guida ma da una settimana non riesco più ad inviare notifiche push, quando lancio il push.php mi appare Internal Server Error…Sapresti aiutarmi?!?!

    Grazie mille per la risposta

    • Internal server error è un errore del tuo server, non dell’app… quindi a meno che tu non mi invii tutto il tuo codice server non posso aiutarti. prova a fare un ini_set degli errori php che ti dice la riga che sbagli

      • Valerio

        Giocando con i commenti ho notato che la stringa che mi crea l’errore è curl_setopt($ch,CURLOPT_URL,$url); commentandola non ho più il server error ma di conseguenza senza url non mi partono le notifiche…ho pensato fosse un errore di google o avessero cambiato url ma non è cosi, anzi su Android Developers suggeriscono di riprovare più tardi, ma sono gia 10 giorni che ho questo problema…

        Grazie per la pronta risposta

  • antonio

    Ciao a tutti,
    vorrei sapere se esiste un limite massimo di dispositivi per l’invio contemporaneo di un messaggio.
    Saluti e grazie per l’interessantissimo articolo.

    • Ciao, ti rispondo di no: google consiglia max 30 connessioni simultanee ma non un max consecutivo.

      • antonio

        grazie

  • Emanule

    Ciao, innanzi tutto grazie per la guida.
    Ho eseguito tutto e non ho nessun errore, l’unico problema è che quando lancio il push.php non succede niente, non ho errori ma neanche arrivano le notifiche.
    Hai consigli?

    • Ciao, detto così no: a parte dirti di controllare la connessione al db, controllare che ci siano dei dati salvati e che la chiave di google sia giusta.

  • Gabriele

    Ciao,
    come posso cancellare i registration id non piu validi? (Per capirci nello script push.php su alcuni device ritorna un errore del tipo {“error”:”NotRegistered”} probabilmente a seguito di disinstallazione dell’applicazione da parte dell’utente).

  • Antonio

    Ciao, io ho un “problema”
    non ho capito come devo modificare la query nel file push
    se ho ben capito è lui che si occupa di selezionare i device che devono ricevere la notifica e nell’esempio che hai fatto seleziona tutti i device che si sono registrati..
    nel mio caso io ho ulteriormente ampliato la tabella che hai creato tu inserendo un ulteriore id che mi identifica i device abbinati a degli account (la logica del mio db è che una persona si registra al mio servizio con un account e con GCM vorrei poter inviare notifiche ad un singolo account, che può avere abbinati + device ovviamente)
    come dovrei fare?
    grazie

    • Ciao, il tuo è più un problema php-mysql: provo a risponderti, per quanto ho capito: devi fare due query innestate, nella prima tiri fuori gli account poi nel while di questa fai la seconda che tira fuori gli id che metterai nell’array come sto facendo io attualmente.

      • Antonio

        si infatti avevo capito che lato client non dovevo modificare niente.
        se gentilmente potresti spiegarmi nel file push.php dalla riga 51, non ho capito che funzione hanno $token, $pushCounter e $registration_id
        mentre ho capito che $registration_ids è l’array che contiene tutti gli id a cui inviare la notifica, giusto?
        grazie della disponibilità

  • Andrea

    @admin: molto bene, grazie mille!

  • Stefano

    Fa niente..ancora troppo difficile come cosa..

    • beh in effetti se sei alle prime armi, aprtire con notifiche e php non è il massimo

  • Stefano

    Scusa, una domanda banale dato che sono alle prime armi. Ma il codice del manifest che hai postato è da copiare tutto? e il namespace.nome_app (i tuoi it.dferrari.notifiche) sono il mio namespace di gmail e il nome dell’app (cioè il tuo è notifiche)?

    • il manifesto è da copiare tutto, anzi andrà espanso perché questa è la base solo per le notifiche.
      il namespace è un nome univoco che ti scegli te, può anche essere weilabellali.applicazione, ma è bnene tenere una logica: la seconda app sarà weilabellali.applicazione2, ok?

  • Giancarlo

    Ciao!
    Sono ancora qui per chiederti un aiuto!
    Ho seguito il tuo tutorial e vorrei aggiungere un PreferenceActivity con un checkbox in modo che l’utente scelga se attivare o meno il servizio. La PreferenceActivity l’ho creata ma non so come richiamare le SharedPreference nell’activity Index in quanto non si possono inserire nel metodo onCreate(). Avresti un suggerimento?
    Grazie
    Giancarlo.

  • Andrea

    Salve, a proposito degli utilizzi: quello che mi lascia perplesso è il payload di 4kb, cosa si può fare (ed è stato fatto) con GCM in un App ?
    Saluti
    Andrea

    • ? non capisco la tua domanda: è un’api da integrare alla fine. puoi farci tutto quello che google e il sistema operativo android ti permette di fare con le notifiche, il resto è alla tua immaginazione.
      http://developer.android.com/google/gcm/index.html

      • Andrea

        in effetti volevo conferma che si trattasse del fatto che si parla solo di notifiche.
        Grazie
        Andrea

      • Andrea

        Di nuovo ciao!

        altra domanda a scoppio ritardato, perchè stavo cercando altre strade, io vorrei fare un app che riceve dati (semplici per cominciare, un msg di testo per es.) da un server remoto, le push notification possono essere una scelta? oppure è il classico cannone per sparare al moscerino?
        grazie in anticipo
        Andrea

      • no, le push così non centrano, anzi credo rovineresti l’esperienza utente. la tua è più una richiesta http tipo un aggiornamento dati da online.

  • Giancarlo

    Ciao,
    complimenti per l’articolo!
    Volevo porti il mio quesito: io posseggo un blog in wordpress e la relativa app per android che scarica le notizie direttamente dai feed. Io vorrei fare in modo che all’inserimento di un nuovo post nel blog arrivi la notifica direttamente sullo smartphone. Potresti darmi qualche dritta? Il file register.php e push.php li devo integrare nel blog in wordpress?
    Grazie.
    Giancarlo

    • Esiste un solo modo: nella tua app devi chiedere all’utente di poter dargli la notifica, e questo ok. poi devi mettere si i files nel server ma per usarli creare un hook in wordpress che, alla pubblicazione di un post, esegua il file che manda le notifiche contenenti una frase che ti inventi te come vuoi (ovviamente). Per l’hook cerca online, ma è tipo:
      add_filter(‘publish_post’, ‘call_my_php_file’);
      function call_my_php_file($post_id){
      $id = $post_id;
      require_once(‘singleJSONgen.php’);
      }
      da mettere nel file functions.php del tuo tema.

      • Giancarlo

        Ti ringrazio!
        un’ultima cosa: la tabella che dici di creare al primo passo del punto 5 è da creare in access?

      • ! no no! è da creare in mysql (phpmyadmin). siamo su php e server linux, non su asp e windows

  • Antonio

    Ciao, finalmente la notifica funziona. L’unica cosa che non funziona è il testo della notifica. Dovrebbe visualizzare “Ciao, sono una notifica!” invece viene visualizzato: “From GCM: you got a message!”

    • Ciao, quasi sicuramente hai un errore nella parte php (che si occupa di scrivere il contenuto, con la variabile $message.
      Non vedo altre possibilità da elencarti.

    • Antonio

      The solution:

      protected void onMessage(Context context, Intent intent) {
      Log.i(TAG, “Received message”);

      // String message = getString(R.string.gcm_message);
      String message = intent.getStringExtra(“price”);

      • ma questo è già così nel mio codice 😉

  • Antonio

    Ciao volevo chiederti come posso fare per far aprire una url dentro l’app. Ho provato in questo modo:

    @Override
    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(“http://sito_web”));
    startActivity(browserIntent);

    Ma quando viene aperta l’app va in errore. Potresti aiutarmi?

    Grazie
    Antonio

    • prova con:
      final Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri.parse(url));
      activity.startActivity(intent);
      però così te lo apre con il browser di android, per aprirlo nell’app devi fare una webview tipo:
      webView = (WebView) findViewById(R.id.webView1);
      webView.getSettings().setJavaScriptEnabled(true);
      webView.loadUrl(“http://www.google.com”);

  • Andrea Falzetti

    Grazie mille per l’articolo. Veramente un ottima risorsa.

    • mi fa molto piacere!

  • Worfut

    Ciao!
    Volevo sapere classe_che_volete.class come lo creo? Cosa deve contenere al suo interno?! A cosa serve?
    Grazie! (molto esaustivo!)

    • Beh lo crei come una qualsiasi altra classe del tuo progetto Android: tasto destro sul package, new, class
      Serve perché è la classe sulla quale viene sparata la persona quando clicca sulla notifica, che ne sò: notifica “guarda le news” cliccata porterà a news.class

  • tar

    Grazie per la risposta.
    il problema è che non mi aspetto che gli utenti abbiano la mail di tutti i contatti quindi pensavo di farlo tramite il numero di telefono, chiaramente se si usa un tablet alla creazione del gruppo bisogna immettere il numero di telefono, speravo pero’ ci fosse un modo piu furbo di farlo magari tramite accountManager di android, pero’ non so se si possa fare

  • tar

    Ciao,
    intanto complimenti per il tutorial, è il migliore che ho trovato in rete fin’ora.
    Tutta la procedura mi è chiara volevo solo chiederti un consiglio.
    La mia app avrebbe bisogno della creazione di gruppi di utenti a cui mandare le notifiche in poche parole un device genera il gruppo (a partire dalla rubrica magari…) i device da notificare sarebbero solo quelli appartenenti al gruppo, avresti qualche suggerimento su come affrontare il problema? come potrei “capire” quali sono i device da notificare? ti ringrazio infinitamente per l’aiuto

    • Ciao, grazie a te 🙂 dunque per quanto ne sò non puoi così. La mia idea, che funziona ma va lavorata un pò: dovresti riuscire in qualche modo a portarti a casa l’email della persona mentre lo registri, o durante l’app in un punto che scegli te, che ne sò, e poi prendere la tua rubrica, prendere tutte le mail che hai li e che sono nel gruppo che mi hai detto, confrontare con il db online se esse esistono e hanno la key, e quindi inviare solo a quell’array di key.

  • ax

    Ok..
    problema risolto (avevo sbagliato io a fare il post di un parametro.
    Ora sorge una nuova domanda..
    come si fa a mandare messaggi multilinea ?

    • mmm… hai provato inserendo uno \r\n ? è solo un’idea eh

  • ax

    Ciao… complimenti e grazie per l’ottimo tutorial (il primo che ho trovato in italiano).
    L’ho provato utilizzando ASP.NET al posto di PHP.
    Funziona tutto perfettamente ma… la notifica mi arriva vuota (nella task ottengo solo l’icona e il titolo dell’app ma non il messaggio)
    invece sul “Toast” nell’ app ricevo messaggio NULL
    sai indicarmi a priori dove sto sbagliando ?
    Lato server o Client ?
    Sul lato server ho dovuto cambiare la stringa del postdata come segue

    string postData = “collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=” + message + “&data.time=” + System.DateTime.Now.ToString() + “&registration_id=” + myrifs;

    Grazie

    • Ciao e grazie per il complimento.
      Guarda, non sono ferrato in ASP, ma se non ti arriva il contenuto del messaggio è problema lato server. l’app android si occupa di prenderla e mostrarla, non cambia ne toglie il contenuto

  • paolo

    salve, grazie per la guida veramente molto ben fatta e dettagliata.
    Ho solo un problema di server: volendo mettere i file su un server aruba mi dice che la funzione curl_init() non è supportata dal server… per caso sapete una funzione alternativa che posso usare per farlo girare liscio ?

    • no, devi dire ad aruba di attivarti l’estensione CURL di php

  • beh sono le cose base di android eclipse… dovresti studiare un pò, credo, prima di fare notifiche push come app.

    comunque: dentro alla cartella dell’app (non sò dove tu abbia impostato il tuo workspace), c’è una cartella chiamata libs (e se non c’è creala), e li ci copi il file .jar.

    dopo, in eclipse clicca col tasto destro sull’app e scegli proprietà: troverai il java buold path, dove potrai dirgli di aggiungere un jar, e selezioni quel file.

  • luca

    .. scusa avevo messo il tuo testo tra i simboli < e non viene visualizzato
    il testo era questo:
    copiare nella cartella della vostra app (io l’ho copiato li e poi l’ho collegato tramite eclipse e il java build path

  • luca

    Ciao, sto seguendo questo tutorial: sono un programmatore php e questo è il mio primo approccio ad una app Android.
    Vorrei qualche spiegazione se possibile:
    Tu dici:

    dove trovo la cartella della mia app e cosa si intende collegarlo tramite eclipse e il java build .. (come si fa ?)
    Grazie.

  • Ccrash

    Ciao, ho implementato il tuo codice e volevo ringraziarti per averlo condiviso, è stato veramente utile 😉
    Volevo segnalarti però che dedicare un varchar(100) per la memorizzazione del registration_id su database potrebbe essere insufficente.
    Nel mio caso l’id occupa un varchar(162) anche se per sicurezza ho preferito dedicare uno spazio varchar(256). In caso contrario l’id salvato viene troncato e il server risponde con {“error”:”InvalidRegistration”}.

    • Ah, non lo sapevo. Non mi era ancora successo un problema simile. Modifico subito l’articolo e… grazie!

  • Salvo

    Ciao, ho provato l’app e funziona. L’unico problema è: come faccio a cancellarmi col cell dalle notifiche?

    • Bene, mi fa piacere!
      Beh per quello puoi semplicemente creare una pagina sul server, che cancella via sql l’utente dalla tabella, e chiamarla dal cellulare via http client:
      HttpClient httpclient = new DefaultHttpClient();
      HttpResponse response = httpclient.execute(new HttpGet(URL));
      StatusLine statusLine = response.getStatusLine();
      if(statusLine.getStatusCode() == HttpStatus.SC_OK){
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      response.getEntity().writeTo(out);
      out.close();
      String responseString = out.toString();
      //..more logic
      } else{
      //Closes the connection.
      response.getEntity().getContent().close();
      throw new IOException(statusLine.getReasonPhrase());
      }
      chiami una pagina come cancellami.php?id=xxx dove l’id lo trovi con il solito final String regId = GCMRegistrar.getRegistrationId(this);

      • Salvo

        Ma non devo usare anche un GCMRegistrar.unregister(getApplicationContext()) o simili?

      • è una questione di scelte. Io, per il fatto che è il mio server, preferisco farlo da me se posso

      • Salvo

        Ah.. ma quindi GCMRegistrar.unregister() serve per eliminare la riga dal DB? Perchè quando lo chiamo, seguendo il tuo tutorial, va a mandarmi una richiesta a register.php/unregister che non so dove sia.

        Inoltre non riesco a mandare una richiesta GET usando questo codice:
        DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
        HttpGet method = new HttpGet();
        method.setURI((new URI(“mio server?regId=” + regId)));
        defaultHttpClient.execute(method);

        E questa è la parte server

        if (isset($_GET[“regId”])) {
        $gcm_regid = $_GET[“regId”]; // GCM Registration ID
        include_once ‘./db_functions.php’;
        include_once ‘./GCM.php’;

        $db = new DB_Functions();
        $db-> removeUserById($gcm_regid);
        } else{
        echo “Inserire Parametri”;
        }

        Il Logcat dice

        02-18 16:51:34.790: W/System.err(2119): android.os.NetworkOnMainThreadException
        02-18 16:51:34.795: W/System.err(2119): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
        02-18 16:51:34.795: W/System.err(2119): at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
        02-18 16:51:34.795: W/System.err(2119): at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
        02-18 16:51:34.800: W/System.err(2119): at java.net.InetAddress.getAllByName(InetAddress.java:214)
        02-18 16:51:34.800: W/System.err(2119): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:137)
        ….

        Che sono le linee dove faccio la richiesta get.. O_o

      • Beh con l’unregister “normale” la richiesta passa prima per android, che poi rimanda al tuo server ad una pagina che dovrai creare. Quindi poco ci cambia dal farlo te con una richiesta http. Riguardo al tuo log, hai tutti i permessi internet nel manifesto? Stai andando su android maggiore del 2.3.3? Se si, devi fare una richiesta asincrona con un thread (infatti da android 3 in su, non si possono fare richieste http nel thread principale… devo anche io aggiustare un pò delle mie app 😉 ). cmq puoi anche non stare a togliere la registrazione di un cellulare, visto che non hai nemmeno inserito una richiesta di attivazione delle stesse.

      • Salvo

        Ho risolto. Era più semplice del previsto.
        Basta richiamare questo:

        Intent unregIntent = new Intent(“com.google.android.c2dm.intent.UNREGISTER”);
        unregIntent.putExtra(“app”, PendingIntent.getBroadcast(this, 0, new Intent(), 0));
        startService(unregIntent);

        Tale chiamata fa scattare un intent di tipo onUnregistered gestito nel file GCMIntentService che richiama il metodo ServerUtilities.unregister(context, registrationId). A questo punto basta far puntare al nostro file cancella.php ed avremo a disposizione i parametri POST per effettuare la cancellazione dal DB.

        Grazie..

      • Si anche. ma capisci che alla fine fai la stessa cosa? Solo che così fai un pitstop all’autogrill di google 😀

      • Salvo

        Si si capito..
        L’unica cosa è l’esecuzione di GCMRegistrar.setRegisteredOnServer(context, false) in modo da essere rimossi anche dai server di BigG.. 😀

  • Purtroppo è un errore che non ho mai visto, quindi mai verificato.
    Ma rispondendoti con il registrationId, vuole sicuramente dire che l’errore è nella parte “smartphone”, non in quella “server”. Ti direi di ricontrollare bene tutto, poi di svuotare il db e riprovare.

  • solos92

    Ciao, ho seguito passo passo il tutorial, l’app parte e il server registra correttamente l’id del telefono, ma quando eseguo il push.php, invece di inviarmi la notifica, da pc ho questo messaggio:

    array(2) { [“registration_ids”]=> array(1) { [0]=> string(100) “APA91bFK_wPMgvhSNmhPYqL2fc-YoyOJvbwiGZSGOw-R_7Q1XJHCF3oPKGPTV7FfuSVadpAQLp0BpnswCuIZbjVm4AYDu0lAIzAD” } [“data”]=> array(1) { [“price”]=> string(24) “Ciao, sono una notifica!” } }
    Unauthorized

    Error 401

    Cosa mi consigli?

    • solos92

      Ho risolto il problema, non avevo inserito correttamente l’api-key nel push.php

      ma ora ho questo messaggio

      array(2) { [“registration_ids”]=> array(1) { [0]=> string(100) “APA91bFK_wPMgvhSNmhPYqL2fc-YoyOJvbwiGZSGOw-R_7Q1XJHCF3oPKGPTV7FfuSVadpAQLp0BpnswCuIZbjVm4AYDu0lAIzAD” } [“data”]=> array(1) { [“price”]=> string(24) “Ciao, sono una notifica!” } } {“multicast_id”:4861109790042621776,”success”:0,”failure”:1,”canonical_ids”:0,”results”:[{“error”:”InvalidRegistration”}]}

      • Ccrash

        Ho avuto lo stesso problema ed ho risolto modificando lo spazio assegnato su db a registration_id da varchar(100) a varchar(256).
        L’errore InvalidRegistration viene riportato quando l’id indicato non corrisponde ad un dispositivo e questo avviene perchè varchar(100) essendo uno spazio insufficente, tronca il valore dell’id.

      • Alessandro

        Come hai risolto?
        Io ho provato a inserire sia la “Key for browser applications” che la “key for Android application”, ma ottengo sempre Unauthorized

        Error 401

      • Questa cosa è misteriosa, era successa anche a me.
        Per risolverla ho provato di tutto, anche a fare un new project.
        Va a culo insomma XD

Back
I cookie ci aiutano a migliorare i nostri servizi. Utilizzando il nostro sito, accetti i cookie sul tuo dispositivo. Più informazioni | Chiudi