Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
laboratoare:laborator08 [2015/04/27 07:32] Andrei Roșu-Cojocaru |
laboratoare:laborator08 [2015/04/27 23:39] (current) Andrei Roșu-Cojocaru |
||
|---|---|---|---|
| Line 28: | Line 28: | ||
| * **o aplicație Android** rulând pe un dispozitiv mobil cu un sistem de operare Android având o versiune mai mare de 2.2, pe care este instalat Google Play Services. | * **o aplicație Android** rulând pe un dispozitiv mobil cu un sistem de operare Android având o versiune mai mare de 2.2, pe care este instalat Google Play Services. | ||
| - | {{ :laboratoare:laborator08:arhitectura_google_cloud_messaging.png?nolink }} | + | {{ :laboratoare:laborator08:arhitectura_google_cloud_messaging.png?nolink&700 }} |
| De regulă, procesul de proiectare și dezvoltare a sistemului informatic implică următorul flux de lucru: | De regulă, procesul de proiectare și dezvoltare a sistemului informatic implică următorul flux de lucru: | ||
| Line 72: | Line 72: | ||
| * Se identifică **numărul de proiect** care va fi utilizat de dispozitivul mobil pentru a se înregistra la serverul Google Cloud Messaging for Android (''SENDER_ID''), acesta putând fi preluat din: | * Se identifică **numărul de proiect** care va fi utilizat de dispozitivul mobil pentru a se înregistra la serverul Google Cloud Messaging for Android (''SENDER_ID''), acesta putând fi preluat din: | ||
| * bara de adrese a aplicației de navigare {{ :laboratoare:laborator08:project_number01.png?nolink }} | * bara de adrese a aplicației de navigare {{ :laboratoare:laborator08:project_number01.png?nolink }} | ||
| - | * secțiunea //Overview// a consolei Google API {{ :laboratoare:laborator08:project_number02.png?nolink&1200 }} | + | * secțiunea //Overview// a consolei Google API {{ :laboratoare:laborator08:project_number02.png?nolink&1000 }} |
| * Se activează API-ul //Cloud Messaging for Android// din secțiunea //Mobile APIs//, ce poate fi accesată din //APIs & auth// → //APIs// a consolei Google API. | * Se activează API-ul //Cloud Messaging for Android// din secțiunea //Mobile APIs//, ce poate fi accesată din //APIs & auth// → //APIs// a consolei Google API. | ||
| Line 91: | Line 91: | ||
| **2.** Se instalează SDK-ul Google Play Services, necesară autentificării / deautentificării la Google Cloud Messaging for Android din cadrul aplicației instalată pe dispozitivul mobil. | **2.** Se instalează SDK-ul Google Play Services, necesară autentificării / deautentificării la Google Cloud Messaging for Android din cadrul aplicației instalată pe dispozitivul mobil. | ||
| - | * În Eclipse Kepler, se accesează ''Android SDK Manager'' | + | * În Eclipse Luna, se accesează //Android SDK Manager// |
| - | * din bara de unelte\\ {{ :laboratoare:lab09-eclipseSDKmanager.jpg?nolink }} | + | * din bara de unelte\\ {{ :laboratoare:laborator08:eclipse_toolbar.png?nolink&900 }} |
| - | * din meniul principal, ''Window'' → ''Android SDK Manager'' | + | * din meniul principal, //Window// → //Android SDK Manager// |
| - | * Se selectează următoarele pachete:\\ {{ :laboratoare:lab09-pacheteSDKmanager.jpg?nolink }} | + | * Se selectează următoarele pachete:\\ {{ :laboratoare:laborator08:android_sdk_manager.png?nolink&600 }} |
| - | * din secțiunea ''Android 4.4.2 (API 19)'', pachetele ''Google APIs'' | + | * din secțiunea ''Android 4.1.2 (API 16)'', pachetul ''Google APIs'' |
| - | * din sețiunea ''Extras'', pachetul ''Google Play Services'' | + | * din sețiunea //Extras//, pachetul //Google Play Services// |
| * Biblioteca pentru accesarea Google Cloud Messaging va fi instalată la ''<android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib''. | * Biblioteca pentru accesarea Google Cloud Messaging va fi instalată la ''<android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib''. | ||
| Line 104: | Line 104: | ||
| * **AVD** | * **AVD** | ||
| - | * se creează un dispozitiv virtual pentru care va specifica la secțiunea ''Target'' valoarea ''Google APIs (Google Inc.)''\\ {{ :laboratoare:lab09-configurareAVD.jpg?nolink }} | + | * se creează un dispozitiv virtual pentru care va specifica la secțiunea //Target// valoarea //Google APIs (Google Inc.)//\\ {{ :laboratoare:laborator08:android_virtual_device01.png?nolink&400 }} |
| - | * se asociază datele unui cont Google (nume de utilizator, parola) din ''Settings'' → ''Accounts'', selectându-se opțiunea ''Add account''\\ {{ :laboratoare:lab09-avd.jpg?nolink }} | + | * se asociază datele unui cont Google (nume de utilizator, parola) din //Settings// → //Accounts//, selectându-se opțiunea //Add account//\\ {{ :laboratoare:laborator08:android_virtual_device02.png?nolink }} |
| * **Genymotion** - vor trebui instalate manual ''ARM Transalation'' și ''Google Apps for Android'' întrucât suportul pentru acestea nu mai este asigurat începând cu versiunea 2.0 | * **Genymotion** - vor trebui instalate manual ''ARM Transalation'' și ''Google Apps for Android'' întrucât suportul pentru acestea nu mai este asigurat începând cu versiunea 2.0 | ||
| - | * în ''Settings'' → ''ADB'' → ''ADB Connection Settings'' se indică locația unde se găsește instalat SDK-ul de Android\\ {{ :laboratoare:lab09-genymotionsettings.jpg?nolink }} | + | * în //Settings// → //ADB// → //ADB Connection Settings// se indică locația unde se găsește instalat SDK-ul de Android\\ {{ :laboratoare:laborator08:genymotion_settings.png?nolink&400 }} |
| * se instalează [[http://pdsd2014.andreirosucojocaru.ro/Genymotion-ARM-Translation_v1.1.zip|ARM Translation 1.1]] printr-o operație de tip drag-and-drop în ecranul principal al emulatorului | * se instalează [[http://pdsd2014.andreirosucojocaru.ro/Genymotion-ARM-Translation_v1.1.zip|ARM Translation 1.1]] printr-o operație de tip drag-and-drop în ecranul principal al emulatorului | ||
| - | * se afișează o fereastră de dialog ce va conține mesajul ''File transfer in progress...''\\ {{ :laboratoare:lab09-genymotionfiletransfer.jpg?nolink }} | + | * se afișează o fereastră de dialog ce va conține mesajul ''File transfer in progress...''\\ {{ :laboratoare:laborator08:file_transfer_in_progress.png?nolink }} |
| - | * odată realizat transferul, se afișează o fereastră de dialog prin care utilizatorul este atenționat de faptul că arhiva ar putea corupe dispozitivul virtual, solicitându-i-se acordul pentru a continua instalarea\\ {{ :laboratoare:lab09-genymotioninstall.jpg?nolink }} | + | * odată realizat transferul, se afișează o fereastră de dialog prin care utilizatorul este atenționat de faptul că arhiva ar putea corupe dispozitivul virtual, solicitându-i-se acordul pentru a continua instalarea\\ {{ :laboratoare:laborator08:arm_translation_warning.png?nolink }} |
| - | * odată realizată instalarea, se afișează o fereastră de dialog ce conține rezultatul operației\\ {{ :laboratoare:lab09-genymotionresult.jpg?nolink }} | + | * odată realizată instalarea, se afișează o fereastră de dialog ce conține rezultatul operației\\ {{ :laboratoare:laborator08:arm_translation_result.png?nolink }} |
| - | * se repornește emulatorul prin comanda\\ <code>adb -s 192.168.56.101:5555 reboot</code> | + | * se repornește emulatorul prin comanda\\ <code>adb -s 192.168.56.101:5555 reboot</code> (sau ''adb reboot<'' dacă există un sigur dispozitiv conectat la un moment dat) |
| - | * se instalează ''Google Apps for Android'' corespunzătoare versiunii sistemului de operare existentă pe dispozitivul virtual, printr-o operație de tip drag-and-drop în ecranul principal al emulatorului (sunt parcurse aceleași etape ca anterior) | + | * se instalează ''Google Apps for Android'' corespunzătoare versiunii sistemului de operare existentă pe dispozitivul virtual, printr-o operație de tip drag-and-drop în ecranul principal al emulatorului (sunt parcurse aceleași etape ca anterior)\\ {{ :laboratoare:laborator08:google_play_services_warning.png?nolink }} \\ {{ :laboratoare:laborator08:google_play_services_result.png?nolink }} |
| * [[http://pdsd2014.andreirosucojocaru.ro/gapps-kk-20140105-signed.zip|Google Apps for Android 4.4]] | * [[http://pdsd2014.andreirosucojocaru.ro/gapps-kk-20140105-signed.zip|Google Apps for Android 4.4]] | ||
| * [[http://pdsd2014.andreirosucojocaru.ro/gapps-jb-20130813-signed.zip|Google Apps for Android 4.3]] | * [[http://pdsd2014.andreirosucojocaru.ro/gapps-jb-20130813-signed.zip|Google Apps for Android 4.3]] | ||
| * [[http://pdsd2014.andreirosucojocaru.ro/gapps-jb-20130812-signed.zip|Google Apps for Android 4.2]] | * [[http://pdsd2014.andreirosucojocaru.ro/gapps-jb-20130812-signed.zip|Google Apps for Android 4.2]] | ||
| * [[http://pdsd2014.andreirosucojocaru.ro/gapps-jb-20121011-signed.zip|Google Apps for Android 4.1]] | * [[http://pdsd2014.andreirosucojocaru.ro/gapps-jb-20121011-signed.zip|Google Apps for Android 4.1]] | ||
| - | * se repornește emulatorul prin comanda\\ <code>adb -s 192.168.56.101:5555 reboot</code> | + | * indiferent de rezultat, se repornește emulatorul prin comanda\\ <code>adb -s 192.168.56.101:5555 reboot</code> (respectiv ''adb reboot'') |
| - | * se asociază datele unui cont Google (nume de utilizator, parola) din ''Settings'' → ''Accounts'', selectându-se opțiunea ''Add account''\\ {{ :laboratoare:lab09-genymotiongoogleaccount.jpg?nolink }} | + | * se asociază datele unui cont Google (nume de utilizator, parola) din //Settings// → //Accounts//, selectându-se opțiunea //Add account//\\ {{ :laboratoare:laborator08:google_account_setup01.png?nolink&400 }}\\ {{ :laboratoare:laborator08:google_account_setup02.png?nolink&400 }}\\ {{ :laboratoare:laborator08:google_account_setup03.png?nolink&400 }}\\ {{ :laboratoare:laborator08:google_account_setup04.png?nolink&400 }}\\ {{ :laboratoare:laborator08:google_account_setup05.png?nolink&400 }}\\ {{ :laboratoare:laborator08:google_account_setup06.png?nolink&400 }}\\ {{ :laboratoare:laborator08:google_account_setup07.png?nolink&400 }}\\ {{ :laboratoare:laborator08:google_account_setup08.png?nolink&400 }}\\ {{ :laboratoare:laborator08:google_account_setup09.png?nolink&400 }} |
| - | * în ''Play Store'' se actualizează toate aplicațiile care necesită acest lucru\\ {{ :laboratoare:lab09-genymotionsoftwareupdate.jpg?nolink }} | + | * se actualizează //Play Store// prin accesarea opțiunii //Settings// de mai multe ori (procesul de actualizare va fi pornit în fundal, în mod automat)\\ {{ :laboratoare:laborator08:google_account_setup10.png?nolink&400 }} |
| - | **4.** În situația în care se va folosi un server CCS (XMPP), este necesară o înregistrare suplimentară pentru a se obține acceptul Google de a utiliza serviciul de transmitere a mesajelor de pe dispozitivul mobil, prin furnizarea informațiilor solicitate la [[https://services.google.com/fb/forms/gcm/|Upstream Google Cloud Messaging and User Notifications Sign-up]]. | + | **4.** În situația în care se va folosi un server CCS (XMPP), în prezent, nu mai este necesară o înregistrare suplimentară pentru a se obține acceptul Google de a utiliza serviciul de transmitere a mesajelor de pe dispozitivul mobil. Anterior, o astfel de solicitare trebuia transmisă la [[https://services.google.com/fb/forms/gcm/|Upstream Google Cloud Messaging and User Notifications Sign-up]]. |
| - | <note warning>Dacă nu se urmează acest pas, va fi transmis un mesaj prin care se refuză conexiunea la server, de tipul ''Project not whitelisted''.</note> | + | ==== Configurare server (opțional) ==== |
| - | + | ||
| - | <note tip>Procesul de aprobare a accesului la acest serviciu poate dura o perioadă de timp mai îndelungată.</note> | + | |
| - | + | ||
| - | ==== Configurare server ==== | + | |
| <note>Pot exista mai multe variante de implementare a unui server de aplicații, în acest caz fiind aleasă o soluție care implică un efort redus de configurare și de implementare propriu-zisă.\\ Ca atare, se va proiecta un server de aplicații care va trimite mesaje către serverul Google Cloud Messaging, respectiv va primi mesaje de la un client Android folosind protocolul HTTP. Pentru dezvoltarea acestei funcționalități, soluția aleasă se bazează pe pagini Internet generate cu **Java Servlets** și utilizând un motor pentru gestiunea bazelor de date **MySQL**, serverul web folosit fiind **Apache Tomcat**.</note> | <note>Pot exista mai multe variante de implementare a unui server de aplicații, în acest caz fiind aleasă o soluție care implică un efort redus de configurare și de implementare propriu-zisă.\\ Ca atare, se va proiecta un server de aplicații care va trimite mesaje către serverul Google Cloud Messaging, respectiv va primi mesaje de la un client Android folosind protocolul HTTP. Pentru dezvoltarea acestei funcționalități, soluția aleasă se bazează pe pagini Internet generate cu **Java Servlets** și utilizând un motor pentru gestiunea bazelor de date **MySQL**, serverul web folosit fiind **Apache Tomcat**.</note> | ||
| - | **5.** Se descarcă cea mai recentă versiune stabilă a serverului web Apache Tomcat ([[http://mirrors.hostingromania.ro/apache.org/tomcat/tomcat-7/v7.0.53/bin/apache-tomcat-7.0.53.zip|zip]]|[[http://mirrors.hostingromania.ro/apache.org/tomcat/tomcat-7/v7.0.53/bin/apache-tomcat-7.0.53.tar.gz|tar.gz]]) și se dezarhivează. | + | **5.** Se descarcă cea mai recentă versiune stabilă a serverului web Apache Tomcat ([[http://mirrors.hostingromania.ro/apache.org/tomcat/tomcat-8/v8.0.21/bin/apache-tomcat-8.0.21.zip|zip]]|[[http://mirrors.hostingromania.ro/apache.org/tomcat/tomcat-8/v8.0.21/bin/apache-tomcat-8.0.21.tar.gz|tar.gz]]) și se dezarhivează. |
| - | **6**. Se descarcă cea mai recentă versiune stabilă a mediului de dezvoltare Eclipse IDE for Java EE Developers (Windows: [[http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/kepler/SR2/eclipse-jee-kepler-SR2-win32.zip|32-bit]]|[[http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/kepler/SR2/eclipse-jee-kepler-SR2-win32-x86_64.zip|64-bit]], Linux: [[http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/kepler/SR2/eclipse-jee-kepler-SR2-linux-gtk.tar.gz|32-bit]]|[[http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/kepler/SR2/eclipse-jee-kepler-SR2-linux-gtk-x86_64.tar.gz|64-bit]]) și se integrează cu serverul web Apache Tomcat. | + | **6**. Se descarcă cea mai recentă versiune stabilă a mediului de dezvoltare Eclipse IDE for Java EE Developers (Windows: [[http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR2/eclipse-jee-luna-SR2-win32.zip|32-bit]]|[[http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR2/eclipse-jee-luna-SR2-win32-x86_64.zip|64-bit]], Linux: [[http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR2/eclipse-jee-luna-SR2-linux-gtk.tar.gz|32-bit]]|[[http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/luna/SR2/eclipse-jee-luna-SR2-linux-gtk-x86_64.tar.gz|64-bit]]) și se integrează cu serverul web Apache Tomcat. |
| - | * ''Window'' → ''Preferences'' → ''Server'' → ''Runtime Environments'' și se accesează butonul ''Add...''\\ {{ :laboratoare:lab09-eclipseEEserverruntimeenvironments.jpg?nolink }} | + | * //Window// → //Preferences// → //Server// → //Runtime Environments// și se accesează butonul //Add...//\\ {{ :laboratoare:laborator08:server_configuration01.png?nolink&500 }} |
| - | * se specifică tipul serverului web (''Apache Tomcat v7.0'')\\ {{ :laboratoare:lab09-eclipseEENewServerRuntimeEnvironment.jpg?nolink }} | + | * se specifică tipul serverului web (''Apache Tomcat v8.0'')\\ {{ :laboratoare:laborator08:server_configuration02.png?nolink&500 }} |
| - | * se precizează locația la care se găsește serverul web (directorul în care a fost dezarhivat, fără alte configurări) și versiunea de Java Runtime Environment\\ {{ :laboratoare:lab09-eclipseEETomcatServer.jpg?nolink }} | + | * se precizează locația la care se găsește serverul web (directorul în care a fost dezarhivat, fără alte configurări) și versiunea de Java Runtime Environment\\ {{ :laboratoare:laborator08:server_configuration03.png?nolink&500 }} |
| <note tip>Se oferă și posibilitatea descărcării și instalării unei instanțe a serverului web Apache Tomcat, însă de regulă aceasta nu referă cea mai recentă versiune.</note> | <note tip>Se oferă și posibilitatea descărcării și instalării unei instanțe a serverului web Apache Tomcat, însă de regulă aceasta nu referă cea mai recentă versiune.</note> | ||
| - | * ''Window'' → ''Show View'' → ''Other...'' → ''Servers'' → ''Server'' și se accesează legătura ''No servers are available. Click this link to create a new server...'' sau click pe butonul drept al mouse-ului în spațiul de lucru ''Server'' → ''New'' → ''Server''\\ {{ :laboratoare:lab09-eclipseEEShowView.jpg?nolink }}\\ {{ :laboratoare:lab09-eclipseEEcreateanewserver.jpg?nolink }} | + | |
| - | * se selectează serverul web definit anterior și se accesează butonul ''Finish''\\ {{ :laboratoare:lab09-eclipseEEdefineanewserver.jpg?nolink }} | + | {{ :laboratoare:laborator08:server_configuration04.png?nolink&500 }} |
| - | * se asociază proiectului un server web pe care va rula: click pe butonul drept al mouse-ului pe denumirea proiectului → ''Properties'' → ''Server'' și se selectează serverul web definit anterior\\ {{ :laboratoare:lab09-eclipseEEprojectproperties.jpg?nolink }} | + | |
| - | * se realizează o referință către biblioteca serverului web, aceasta fiind trecută în classpath: click pe butonul drept al mouse-ului pe denumirea proiectului → ''Build Path'' → ''Add Library'' | + | * //Window// → //Show View// → //Other...// → //Servers// → //Server// și se accesează legătura //No servers are available. Click this link to create a new server...// sau click pe butonul drept al mouse-ului în spațiul de lucru //Server// → //New// → //Server//\\ {{ :laboratoare:laborator08:server_configuration05.png?nolink }}\\ {{ :laboratoare:laborator08:server_configuration06.png?nolink&800 }} |
| - | * se alege ''Server Runtime''\\ {{ :laboratoare:lab09-eclipseEEAddLibrary.jpg?nolink }} | + | * se selectează serverul web definit anterior și se accesează butonul //Finish//\\ {{ :laboratoare:laborator08:server_configuration07.png?nolink&500 }} |
| - | * se indică serverul web definit anterior și se accesează butonul ''Finish''\\ {{ :laboratoare:lab09-eclipseEEServerLibrary.jpg?nolink }} | + | * se asociază proiectului un server web pe care va rula: click pe butonul drept al mouse-ului pe denumirea proiectului → //Properties// → //Server// și se selectează serverul web definit anterior\\ {{ :laboratoare:laborator08:server_configuration08.png?nolink&500 }} |
| + | * se realizează o referință către biblioteca serverului web, aceasta fiind trecută în classpath: click pe butonul drept al mouse-ului pe denumirea proiectului → //Build Path// → //Add Library// | ||
| + | * se alege //Server Runtime//\\ {{ :laboratoare:laborator08:server_configuration09.png?nolink&500 }} | ||
| + | * se indică serverul web definit anterior și se accesează butonul ''Finish''\\ {{ :laboratoare:laborator08:server_configuration10.png?nolink&500 }} | ||
| **7.** Se descarcă și se instalează cea mai recentă versiune stabilă a motorului pentru baze de date MySQL. | **7.** Se descarcă și se instalează cea mai recentă versiune stabilă a motorului pentru baze de date MySQL. | ||
| - | * Windows: se poate folosi [[http://dev.mysql.com/get/Downloads/MySQLInstaller/mysql-installer-community-5.6.17.0.msi|MySQL Community Server]]. | + | * Windows: se poate folosi [[https://dev.mysql.com/get/Downloads/MySQLInstaller/mysql-installer-community-5.7.7.0-rc.msi|MySQL Community Server]]. |
| - | * Linux: se poate utiliza comanda <code>sudo apt-get install mysql-server</code> | + | * Linux: se poate utiliza comanda <code>student@pdsd2015:~$ sudo apt-get install mysql-server</code> |
| <note>Configurarea propriu-zisă nu presupune decât specificarea unei parole de administrare.</note> | <note>Configurarea propriu-zisă nu presupune decât specificarea unei parole de administrare.</note> | ||
| - | Pentru gestiunea propriu-zisă a bazelor de date, poate fi utiliza MySQL Workbench [[http://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.1.4-win32.msi|Windows]]|[[http://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.1.4-1ubu1204-i386.deb|Ubuntu]]|[[http://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.1.4-1.fc19.i686.rpm|Fedora Core]]|[[http://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.1.4-1.el6.i686.rpm|Red Hat]].\\ De asemenea, se poate accesa consola MySQL folosind comanda <code>mysql -u root -p</code> | + | Pentru gestiunea propriu-zisă a bazelor de date, poate fi utiliza MySQL Workbench [[https://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.3.3-win32.msi|Windows]]|[[https://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.3.3-1ubu1410-amd64.deb|Ubuntu]]|[[https://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.3.3-1.el7.x86_64.rpm|Fedora Core]]|[[https://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.3.3-1.fc21.x86_64.rpm|Red Hat]], [[https://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-workbench-community-6.3.3-osx-x86_64.dmg|Mac OS X]]. |
| + | |||
| + | De asemenea, se poate accesa consola MySQL folosind comanda <code>student@pdsd2015:~$ mysql -u root -p</code> | ||
| Va trebui indicată parola, atunci când aceasta este solicitată. | Va trebui indicată parola, atunci când aceasta este solicitată. | ||
| - | === MySQL pe Debian Wheezy === | ||
| - | |||
| - | * in cazul in care nu exista, se instaleaza pachetul ''libaio1'' <code> | ||
| - | sudo apt-get install libaio1 | ||
| - | </code> | ||
| - | |||
| - | * se descarca versiunea corespunzatoare arhitecturii pe care se doreste sa se instaleze serverul MySQL pentru gestiunea bazei de date ([[http://dev.mysql.com/downloads/file.php?id=451433|32-bit]]|[[http://dev.mysql.com/downloads/file.php?id=451434|64-bit]]). | ||
| - | |||
| - | * se instaleaza pachetul in ''/opt/mysql/server-5.6'' <code> | ||
| - | sudo dpkg -i mysql-5.6.17-debian6.0-<arhitectura>.deb | ||
| - | </code> | ||
| - | |||
| - | * se copiaza fisierul de configurare ''my-default.cnf'' in ''/etc'', astfel incat acesta sa fie utilizat atunci cand se vor rula script-urile MySQL <code> | ||
| - | sudo cp /opt/mysql/server-5.6/support-files/my-default.cnf /etc/my.cnf | ||
| - | </code> | ||
| - | |||
| - | * se editeaza fisierul de configurare ''/etc/my.cnf'' <code> | ||
| - | gedit /etc/my.cnf | ||
| - | |||
| - | basedir = /opt/mysql/server-5.6 | ||
| - | #datadir = ..... | ||
| - | port = 3306 | ||
| - | #server_id = ..... | ||
| - | #socket = ..... | ||
| - | </code> | ||
| - | |||
| - | * se specifica calea catre binare <code> | ||
| - | sudo gedit /etc/profile | ||
| - | |||
| - | PATH=/opt/mysql/server-5.6/bin:$PATH | ||
| - | </code> | ||
| - | |||
| - | <note important>Incarcarea acestor configurari va fi realizata in momentul in care se realizeaza autentificarea unui utilizator in cadrul sistemului de operare sau se ruleaza in terminal ''. /etc/profile''.</note> | ||
| - | |||
| - | * se creeaza grupul si utilizatorul ''mysql'', care va primi drepturi asupra directorului ''/opt/mysql'' <code> | ||
| - | sudo groupadd mysql | ||
| - | sudo useradd -r -g mysql mysql | ||
| - | cd /opt/mysql | ||
| - | sudo chown -R mysql.mysql /opt/mysql | ||
| - | sudo chgrp -R mysql /opt/mysql | ||
| - | </code> | ||
| - | |||
| - | * se ruleaza script-urile pentru configurarea propriu-zisa a serverului MySQL pentru gestiunea bazei de date <code> | ||
| - | cd /opt/mysql/server-5.6/scripts | ||
| - | sudo ./mysql_install_db --user=mysql | ||
| - | mysqld_safe --user=mysql | ||
| - | mysql_secure_installation | ||
| - | </code> | ||
| - | |||
| - | * se realizeaza configurarile necesare pentru ca serverul pentru gestiunea bazei de date sa porneasca / sa se opreasca odata cu sistemul de operare <code> | ||
| - | sudo cp /opt/mysql/server-5.6/support-files/mysql.server /etc/init.d/mysql.server | ||
| - | cd /etc/init.d | ||
| - | sudo chmod 755 mysql.server | ||
| - | sudo inssev mysql.server | ||
| - | </code> | ||
| ===== Proiectarea și dezvoltarea clientului ===== | ===== Proiectarea și dezvoltarea clientului ===== | ||
| Line 216: | Line 162: | ||
| <note warning>Există posibilitatea ca rularea proiectului Eclipse să necesite mai multă memorie ce trebuie alocată mașinii virtuale Java, aceasta realizându-se prin intermediul valorilor furnizate în cadrul fișierului de configurare ''eclipse.ini'':\\ <code> | <note warning>Există posibilitatea ca rularea proiectului Eclipse să necesite mai multă memorie ce trebuie alocată mașinii virtuale Java, aceasta realizându-se prin intermediul valorilor furnizate în cadrul fișierului de configurare ''eclipse.ini'':\\ <code> | ||
| --launcher.XXMaxPermSize | --launcher.XXMaxPermSize | ||
| - | 512M | + | 1024M |
| --launcher.XXMaxPermSize | --launcher.XXMaxPermSize | ||
| - | 512m | + | 1024m |
| --launcher.appendVmargs | --launcher.appendVmargs | ||
| -vmargs | -vmargs | ||
| - | -Dosgi.requiredJavaVersion=1.6 | + | -Dosgi.requiredJavaVersion=1.7 |
| - | -Xms512m | + | -Xms1024m |
| -Xmx1024m | -Xmx1024m | ||
| </code> | </code> | ||
| Line 228: | Line 174: | ||
| Se realizează o referință către biblioteca pentru accesarea Google Cloud Messaging care este localizată în ''<android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib'' | Se realizează o referință către biblioteca pentru accesarea Google Cloud Messaging care este localizată în ''<android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib'' | ||
| - | * se accesează ''File'' → ''Import'' → ''Android'' → ''Existing Android Code Into Workspace''\\ {{ :laboratoare:lab09-eclipseimportandroidcode.jpg?nolink }} | + | * se accesează //File// → //Import// → //Android// → //Existing Android Code Into Workspace//\\ {{ :laboratoare:laborator08:google_cloud_messaging_library_import01.png?nolink&500 }} |
| - | * se indică locația unde se găsește instalată biblioteca pentru accesarea Google Cloud Messaging, creându-se o copie a acestuia în spațiul de lucru (se bifează opțiunea ''Copy projects into workspace'')\\ {{ :laboratoare:lab09-eclipseimportandroidproject.jpg?nolink }} | + | * se indică locația unde se găsește instalată biblioteca pentru accesarea Google Cloud Messaging, creându-se o copie a acestuia în spațiul de lucru (se bifează opțiunea //Copy projects into workspace//)\\ {{ :laboratoare:laborator08:google_cloud_messaging_library_import02.png?nolink&800 }} |
| - | * în fereastra corespunzătoare proiectului (click dreapta pe denumirea proiectului în ''Package Explorer'' → ''Properties''), se accesează opțiunea ''Android'' și se specifică referința către biblioteca respectivă în secțiunea ''Library'' (accesând butonul ''Add'')\\ {{ :laboratoare:lab09-eclipseprojectproperties.jpg?nolink }} | + | * în fereastra corespunzătoare proiectului aferent aplicației Android (click dreapta pe denumirea proiectului în //Package Explorer// → //Properties//), se accesează opțiunea //Android// și se specifică referința către biblioteca respectivă în secțiunea //Library// (accesând butonul //Add//)\\ {{ :laboratoare:laborator08:google_cloud_messaging_library_import03.png?nolink&800 }} |
| ==== Structura Proiectului ==== | ==== Structura Proiectului ==== | ||
| Line 237: | Line 183: | ||
| - o **activitate** (''GoogleCloudMessagingActivity'') care: | - o **activitate** (''GoogleCloudMessagingActivity'') care: | ||
| - verifică dacă pe dispozitivul mobil este instalat Google Play Services și dacă această aplicație este actualizată; | - verifică dacă pe dispozitivul mobil este instalat Google Play Services și dacă această aplicație este actualizată; | ||
| - | - permite înregistrarea dispozitivului mobil la serverul Google Cloud Messaging dacă această operație nu a fost realizată în prealabil (o astfel de informație ar trebui stocată în SharedPreferences astfel încât operația să fie realizată o singură dată); | + | - permite înregistrarea dispozitivului mobil la serverul Google Cloud Messaging dacă această operație nu a fost realizată în prealabil (o astfel de informație ar trebui stocată în ''SharedPreferences'' astfel încât operația să fie realizată o singură dată); |
| - | - transmite identificatorul de înregistrare obținut către serverul de aplicații (împreună cu alte informații prin care să poată fi recunoscut dispozitivul mobil - de exemplu, un nume de utilizator sau o adresă de posță electronică) | + | - transmite identificatorul de înregistrare obținut către serverul de aplicații (împreună cu alte informații prin care să poată fi recunoscut dispozitivul mobil - de exemplu, un nume de utilizator sau o adresă de posță electronică); |
| - | - un **ascultător** pentru mesajele cu difuzare (''GoogleCloudMessagingBroadcastReceiver'') către care este livrat un mesaj transmis de serverul Google Cloud Messaging, prin intermediul unei intenții | + | - un **ascultător** pentru mesajele cu difuzare (''GoogleCloudMessagingBroadcastReceiver'') către care este livrat un mesaj transmis de serverul Google Cloud Messaging, prin intermediul unei intenții; |
| - (opțional) un **serviciu** (''GoogleCloudMessagingIntentService'') lansat în execuție în momentul în care este livrat mesajul (de către ascultător) în cadrul căruia acesta este procesat propriu-zis; utilizarea unui serviciu este necesară doar în situația în care prelucrarea mesajului se realizează într-un interval de timp mai mare, fiind necesar să se asigure faptul că dispozitivul mobil nu devine inactiv între timp. | - (opțional) un **serviciu** (''GoogleCloudMessagingIntentService'') lansat în execuție în momentul în care este livrat mesajul (de către ascultător) în cadrul căruia acesta este procesat propriu-zis; utilizarea unui serviciu este necesară doar în situația în care prelucrarea mesajului se realizează într-un interval de timp mai mare, fiind necesar să se asigure faptul că dispozitivul mobil nu devine inactiv între timp. | ||
| - | {{ :laboratoare:lab09-structuraproiectului.jpg?nolink }} | + | {{ :laboratoare:laborator08:package_explorer.png?nolink&500 }} |
| === Activitatea GoogleCloudMessagingActivity === | === Activitatea GoogleCloudMessagingActivity === | ||
| Line 248: | Line 194: | ||
| Pe lângă implementarea interfeței grafice prin care se asigură interacțiunea cu utilizatorul, activitatea ''GoogleCloudMessagingActivity'' este responsabilă pentru: | Pe lângă implementarea interfeței grafice prin care se asigură interacțiunea cu utilizatorul, activitatea ''GoogleCloudMessagingActivity'' este responsabilă pentru: | ||
| - | **1.** verificarea compatibilității dispozitivului mobil pe care rulează aplicația cu Google Play Services, SDK pe care se bazează Google Cloud Messaging; această operație trebuie să se realizeze la crearea activității (metoda ''onCreate()'') dar și în cazul revenirii la aceasta prin alte mijloace (metoda ''onResume()'') | + | **1.** verificarea compatibilității dispozitivului mobil pe care rulează aplicația cu Google Play Services, SDK pe care se bazează Google Cloud Messaging; această operație trebuie să se realizeze în momentul în care aplicația devine vizibilă (deci pe metoda ''onResume()''), astfel încât și în situația în care activitatea a fost întreruptă, să se identifice situația în care aceasta a fost instalată sau actualizată: |
| <code java> | <code java> | ||
| private boolean checkPlayServices() { | private boolean checkPlayServices() { | ||
| - | int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); | + | int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); |
| - | if (resultCode != ConnectionResult.SUCCESS) { | + | if (resultCode != ConnectionResult.SUCCESS) { |
| - | if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { | + | if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { |
| - | GooglePlayServicesUtil.getErrorDialog(resultCode, this, Configuration.PLAY_SERVICES_RESOLUTION_REQUEST).show(); | + | GooglePlayServicesUtil.getErrorDialog(resultCode, this, Configuration.PLAY_SERVICES_RESOLUTION_REQUEST).show(); |
| - | } else { | + | } else { |
| - | Log.i(TAG, "This mobile device does not support Google Play Services."); | + | Log.i(Constants.TAG, Constants.GOOGLE_PLAY_SERVICES_ERROR_MESSAGE2); |
| - | finish(); | + | finish(); |
| - | } | + | |
| - | return false; | + | |
| } | } | ||
| - | return true; | + | return false; |
| + | } | ||
| + | return true; | ||
| } | } | ||
| </code> | </code> | ||
| Line 272: | Line 218: | ||
| <code java> | <code java> | ||
| private void registerInBackground() { | private void registerInBackground() { | ||
| - | new AsyncTask<Object, Integer, String>() { | + | new AsyncTask<Object, Integer, String>() { |
| - | @Override | + | @Override |
| - | protected String doInBackground(Object... params) { | + | protected String doInBackground(Object... params) { |
| - | try { | + | try { |
| - | if (googleCloudMessaging == null) { | + | if (googleCloudMessaging == null) { |
| - | googleCloudMessaging = GoogleCloudMessaging.getInstance(context); | + | googleCloudMessaging = GoogleCloudMessaging.getInstance(context); |
| - | } | + | } |
| - | registrationId = googleCloudMessaging.register(Configuration.PROJECT_NUMBER); | + | registrationId = googleCloudMessaging.register(Configuration.PROJECT_NUMBER); |
| - | // store the registration ID into the SharedPreferences | + | // store the registration ID into the SharedPreferences |
| - | // the ID is not yet registered with the application server | + | // the ID is not yet registered with the application server |
| - | setSharedPreferences(context, registrationId, Configuration.FAILURE); | + | Utilities.setInformationIntoSharedPreferences(GoogleCloudMessagingActivity.this, registrationId, Constants.FAILURE); |
| - | } catch (IOException exception) { | + | } catch (IOException ioException) { |
| - | registrationId = "an exception has occurred: " + exception.getMessage(); | + | registrationId = "An exception has occurred: " + ioException.getMessage(); |
| - | exception.printStackTrace(); | + | if (Constants.DEBUG) { |
| - | } | + | ioException.printStackTrace(); |
| - | return registrationId; | + | } |
| - | } | + | } |
| - | + | return registrationId; | |
| - | @Override | + | } |
| - | protected void onPostExecute(String registrationId) { | + | |
| - | registrationIdTextViewValue.append(registrationId + "\n"); | + | @Override |
| - | Log.i(TAG, "registration ID supplied by the Google Cloud Messaging Server is: "+registrationId); | + | protected void onPostExecute(String registrationId) { |
| - | } | + | Log.i(Constants.TAG, Constants.REGISTRATION_ID_INFORMATION_MESSAGE + registrationId); |
| - | }.execute(null, null, null); | + | if (unregisteredFragment != null) { |
| + | unregisteredFragment.setRegistrationIdTextView(registrationId); | ||
| + | } | ||
| + | } | ||
| + | }.execute(null, null, null); | ||
| } | } | ||
| </code> | </code> | ||
| - | <note warning>Întrucât procesul de înregistrare la Google Cloud Messaging implică comunicație prin rețea, este necesar ca acesta să se realizeze asincron, pe un fir de execuție separat, motiv pentru care procesarea a fost realizată în cadrul metodei ''doInBackground'' a unui obiect de tip ''AsyncTask''.</note> | + | <note warning>Întrucât procesul de înregistrare la Google Cloud Messaging implică comunicație prin rețea, este necesar ca acesta să se realizeze asincron, pe un fir de execuție separat, motiv pentru care procesarea a fost realizată în cadrul metodei ''doInBackground()'' a unui obiect de tip ''AsyncTask''.</note> |
| Testarea existenței unei valori corespunzătoare identificatorului de înregistrare în preferințele utilizatorului se face foarte ușor, acesta având o structură de tip asociere între o cheie și o valoare. | Testarea existenței unei valori corespunzătoare identificatorului de înregistrare în preferințele utilizatorului se face foarte ușor, acesta având o structură de tip asociere între o cheie și o valoare. | ||
| <code java> | <code java> | ||
| - | private String getRegistrationId(Context context) { | + | public static String getRegistrationIdFromSharedPreferences(Context context) { |
| - | final SharedPreferences sharedPreferences = getSharedPreferences(context); | + | final SharedPreferences sharedPreferences = getSharedPreferences(context); |
| - | String registrationId = sharedPreferences.getString(Configuration.REGISTRATION_ID_PROPERTY, ""); | + | String registrationId = sharedPreferences.getString(Constants.REGISTRATION_ID_PROPERTY, ""); |
| - | if (registrationId.isEmpty()) { | + | if (registrationId.isEmpty()) { |
| - | Log.i(TAG, "Registration ID not found into the SharedPreferences."); | + | Log.i(Constants.TAG, Constants.REGISTRATION_ID_ERROR_MESSAGE); |
| - | return ""; | + | return Constants.EMPTY_STRING; |
| - | } | + | } |
| - | // check whether the application was updated | + | // check whether the application was updated |
| - | // if it is the case, the registration ID previously supplied must be cleared | + | // if it is the case, the registration ID previously supplied must be cleared |
| - | // as it is not guaranteed to work with the current version | + | // as it is not guaranteed to work with the current version |
| - | int registeredVersion = sharedPreferences.getInt(Configuration.APPLICATION_VERSION_PROPERTY, Integer.MIN_VALUE); | + | int registeredApplicationVersion = sharedPreferences.getInt(Constants.APPLICATION_VERSION_PROPERTY, Integer.MIN_VALUE); |
| - | int currentVersion = getApplicationVersion(context); | + | int currentVersion = getApplicationVersion(context); |
| - | if (registeredVersion != currentVersion) { | + | if (registeredApplicationVersion != currentVersion) { |
| - | Log.i(TAG, "The application version was changed."); | + | Log.i(Constants.TAG, Constants.APPLICATION_VERSION_ERROR_MESSAGE); |
| - | return ""; | + | return Constants.EMPTY_STRING; |
| - | } | + | } |
| - | return registrationId; | + | return registrationId; |
| } | } | ||
| </code> | </code> | ||
| Line 329: | Line 279: | ||
| <code java> | <code java> | ||
| - | public static class RegisterButtonListener implements OnClickListener { | + | protected class SendRegistrationIdButtonClickListener implements Button.OnClickListener { |
| - | @Override | + | |
| - | public void onClick(View view) { | + | @Override |
| - | new AsyncTask<Object, Integer, Integer>() { | + | public void onClick(View view) { |
| - | @Override | + | new AsyncTask<Object, Integer, Integer>() { |
| - | protected Integer doInBackground(Object... params) { | + | @Override |
| - | try { | + | protected Integer doInBackground(Object... params) { |
| - | HttpClient httpClient = new DefaultHttpClient(); | + | |
| - | + | try { | |
| - | HttpPost httpPost = new HttpPost(Configuration.GOOGLECLOUDMESSAGING_WEBSERVER_URL); | + | HttpClient httpClient = new DefaultHttpClient(); |
| - | + | ||
| - | // send the username, email and registration ID as fields of the HTTP body | + | HttpPost httpPost = new HttpPost(Constants.DEVICE_REGISTRATION_SERVICE_ADDRESS); |
| - | // to the application server | + | |
| - | List<NameValuePair> requestParameters = new ArrayList<NameValuePair>(); | + | // send the user name, email and registration ID as fields of the HTTP body to the application server |
| - | requestParameters.add(new BasicNameValuePair(Configuration.USER_NAME, usernameEditText.getText().toString())); | + | List<NameValuePair> requestParameters = new ArrayList<NameValuePair>(); |
| - | requestParameters.add(new BasicNameValuePair(Configuration.EMAIL, emailEditText.getText().toString())); | + | requestParameters.add(new BasicNameValuePair(Constants.USERNAME, usernameEditText.getText().toString())); |
| - | requestParameters.add(new BasicNameValuePair(Configuration.REGISTRATION_ID, registrationIdTextViewValue.getText().toString())); | + | requestParameters.add(new BasicNameValuePair(Constants.EMAIL, emailEditText.getText().toString())); |
| - | UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(requestParameters, HTTP.UTF_8); | + | requestParameters.add(new BasicNameValuePair(Constants.REGISTRATION_ID, registrationIdTextView.getText().toString())); |
| - | httpPost.setEntity(urlEncodedFormEntity); | + | |
| - | + | UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(requestParameters, HTTP.UTF_8); | |
| - | HttpResponse httpPostResponse = httpClient.execute(httpPost); | + | httpPost.setEntity(urlEncodedFormEntity); |
| - | + | ||
| - | // transmission of information to the application server was successful | + | HttpResponse httpPostResponse = httpClient.execute(httpPost); |
| - | if (httpPostResponse.getStatusLine().getStatusCode() == 200) | + | |
| - | return Configuration.SUCCESS; | + | // transmission of information to the application server was successful |
| - | } catch (Exception exception) { | + | if (httpPostResponse.getStatusLine().getStatusCode() == 200) { |
| - | Log.e(TAG, exception.getMessage()); | + | return Constants.SUCCESS; |
| - | exception.printStackTrace(); | + | } |
| - | } | + | } catch (IOException ioException) { |
| - | // transmission of information to the application server was not successful | + | Log.e(Constants.TAG, "An exception has occurred: " + ioException.getMessage()); |
| - | return Configuration.FAILURE; | + | if (Constants.DEBUG) { |
| - | } | + | ioException.printStackTrace(); |
| + | } | ||
| + | } | ||
| + | // transmission of information to the application server was not successful | ||
| + | return Constants.FAILURE; | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | protected void onPostExecute(Integer result) { | ||
| + | switch(result.intValue()) { | ||
| + | case Constants.SUCCESS: | ||
| + | // store the registration ID into the SharedPreferences | ||
| + | // the ID is registered with the application server | ||
| + | Utilities.setInformationIntoSharedPreferences(getActivity(), registrationIdTextView.getText().toString(), Constants.SUCCESS); | ||
| | | ||
| - | @Override | + | // replace the existing fragment in order to forbid the user to register its ID to the registration server |
| - | protected void onPostExecute(Integer result) { | + | RegisteredFragment registeredFragment = new RegisteredFragment(); |
| - | // ... | + | FragmentManager fragmentManager = getActivity().getFragmentManager(); |
| - | } | + | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); |
| - | }.execute(null, null, null); | + | fragmentTransaction.replace(R.id.container, registeredFragment); |
| - | } | + | fragmentTransaction.commit(); |
| + | Log.i(Constants.TAG, Constants.REGISTRATION_PROCESS_SUCCESS); | ||
| + | break; | ||
| + | |||
| + | case Constants.FAILURE: | ||
| + | Log.i(Constants.TAG, Constants.REGISTRATION_PROCESS_FAILURE); | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | }.execute(null, null, null); | ||
| + | } | ||
| } | } | ||
| </code> | </code> | ||
| Line 378: | Line 351: | ||
| Implementarea unui ascultător pentru mesaje cu difuzare poate fi realizată în două variante: | Implementarea unui ascultător pentru mesaje cu difuzare poate fi realizată în două variante: | ||
| - | - în cazul în care procesarea mesajului implică operații triviale (ce pot fi realizate într-un interval de timp rezonabil), se poate defini un ascultător ''BroadcastReceiver'', prelucrarea propriu-zisă realizându-se în cadrul metodei ''onReceive'' (ce primește ca parametri contextul și intenția care a apelat-o, cu informațiile din corpul mesajului atașate într-un obiect de tip ''Bundle''), apelată în mod automat în momentul în care mesajul este livrat. | + | - în cazul în care procesarea mesajului implică operații triviale (ce pot fi realizate într-un interval de timp rezonabil), se poate defini un ascultător ''BroadcastReceiver'', prelucrarea propriu-zisă realizându-se în cadrul metodei ''onReceive()'' (ce primește ca parametri contextul și intenția care a apelat-o, cu informațiile din corpul mesajului atașate într-un obiect de tip ''Bundle''), apelată în mod automat în momentul în care mesajul este livrat. |
| - | - în situația în care procesarea mesajului presupune mai multe operații realizate într-un interval de timp semnificativ, prelucrarea se va realiza în cadrul unui serviciu dedicat (de tip ''IntentService''), ce va rula în fundal, în timp ce se obține accesul la un tip de mutex ce împiedică dispozitivul mobil să intre într-o stare de inactivitate care ar suspenda tratarea evenimentului de livrare a unui mesaj, dacă aceasta nu este încă completată: <code java> | + | - în situația în care procesarea mesajului presupune mai multe operații realizate într-un interval de timp semnificativ, prelucrarea se va realiza în cadrul unui serviciu dedicat (de tip ''IntentService''), ce va rula în fundal, în timp ce se obține accesul la un tip de mutex ce împiedică dispozitivul mobil să intre într-o stare de inactivitate care ar suspenda tratarea evenimentului de livrare a unui mesaj, dacă aceasta nu este încă completată: <file java GoogleCloudMessagingBroadcastReceiver.java> |
| public class GoogleCloudMessagingBroadcastReceiver extends WakefulBroadcastReceiver { | public class GoogleCloudMessagingBroadcastReceiver extends WakefulBroadcastReceiver { | ||
| - | @Override | + | |
| - | public void onReceive(Context context, Intent intent) { | + | @Override |
| - | // create a component associated to the service that will handle the intent | + | public void onReceive(Context context, Intent intent) { |
| - | ComponentName component = new ComponentName(context.getPackageName(), GoogleCloudMessagingIntentService.class.getName()); | + | |
| - | // start the service | + | // create a component associated to the service that will handle the intent |
| - | // maintain the mobile device awake | + | ComponentName component = new ComponentName( |
| - | startWakefulService(context, (intent.setComponent(component))); | + | context.getPackageName(), |
| - | setResultCode(Activity.RESULT_OK); | + | GoogleCloudMessagingIntentService.class.getName() |
| - | } | + | ); |
| + | |||
| + | // start the service | ||
| + | // maintain the mobile device awake | ||
| + | startWakefulService(context, (intent.setComponent(component))); | ||
| + | setResultCode(Activity.RESULT_OK); | ||
| + | } | ||
| } | } | ||
| - | </code>Așa cum se poate observa, a fost utilizat un ascultător de tip ''WakefulBroadcastReceiver'', delegarea procesării mesajului către serviciul dedicat făcându-se prin metoda ''startWakefulService'' ce asigură și obținerea accesului la mutexul care împiedică intrarea dispozitivului mobil într-o stare de inactivitate. | + | </file> |
| + | |||
| + | Așa cum se poate observa, a fost utilizat un ascultător de tip ''WakefulBroadcastReceiver'', delegarea procesării mesajului către serviciul dedicat făcându-se prin metoda ''startWakefulService'' ce asigură și obținerea accesului la mutexul care împiedică intrarea dispozitivului mobil într-o stare de inactivitate. | ||
| === Serviciul GoogleCloudMessagingIntentService === | === Serviciul GoogleCloudMessagingIntentService === | ||
| Line 397: | Line 378: | ||
| În cadrul serviciului pentru tratarea evenimentului (de tip ''IntentService'') are loc procesarea propriu-zisă a mesajului, aceasta fiind realizată în cadrul metodei ''onHandleIntent()'' care primește ca parametru aceeași intenție care a fost transmisă ascultătorului, și pentru care a fost obținut mutextul care împiedică intrarea dispozitivului mobil într-o stare de inactivitate. | În cadrul serviciului pentru tratarea evenimentului (de tip ''IntentService'') are loc procesarea propriu-zisă a mesajului, aceasta fiind realizată în cadrul metodei ''onHandleIntent()'' care primește ca parametru aceeași intenție care a fost transmisă ascultătorului, și pentru care a fost obținut mutextul care împiedică intrarea dispozitivului mobil într-o stare de inactivitate. | ||
| - | Prelucrarea unui mesaj se face în funcție de tipul acestuia, furnizat de metoda ''getMessageType'' a obiectului de tip ''GoogleCloudMessaging'', pe baza informațiilor din intenție. Odată cunoscut tipul mesajului și datele asociate prin ''Bundle'', utilizatorul poate realiza orice acțiune, de la transmiterea unei notificări la modificarea conținutului unor controale grafice din cadrul activității. | + | Prelucrarea unui mesaj se face în funcție de tipul acestuia, furnizat de metoda ''getMessageType()'' a obiectului de tip ''GoogleCloudMessaging'', pe baza informațiilor din intenție. Odată cunoscut tipul mesajului și datele asociate prin ''Bundle'', utilizatorul poate realiza orice acțiune, de la transmiterea unei notificări la modificarea conținutului unor controale grafice din cadrul activității. |
| <note important>Ulterior analizei mesajului, trebuie să se asigure și eliberarea mutexului ce împiedică intrarea dispozitivului mobil într-o stare de inactivitate, prin apelul metodei ''completeWakefulIntent()'' căreia i se transmite ca parametru aceeași intenție pentru care a fost obținută această resursă.</note> | <note important>Ulterior analizei mesajului, trebuie să se asigure și eliberarea mutexului ce împiedică intrarea dispozitivului mobil într-o stare de inactivitate, prin apelul metodei ''completeWakefulIntent()'' căreia i se transmite ca parametru aceeași intenție pentru care a fost obținută această resursă.</note> | ||
| - | <code java> | + | <file java GoogleCloudMessagingIntentService.java> |
| public class GoogleCloudMessagingIntentService extends IntentService { | public class GoogleCloudMessagingIntentService extends IntentService { | ||
| - | private final static String TAG = "GoogleCloudMessagingIntentService"; | + | public GoogleCloudMessagingIntentService() { |
| - | + | super(Constants.TAG); | |
| - | public GoogleCloudMessagingIntentService() { | + | } |
| - | super(TAG); | + | |
| + | @Override | ||
| + | protected void onHandleIntent(Intent intent) { | ||
| + | // the intent is supplied via the BroadcastReceiver | ||
| + | |||
| + | GoogleCloudMessaging googleCloudMessaging = GoogleCloudMessaging.getInstance(this); | ||
| + | |||
| + | String messageType = googleCloudMessaging.getMessageType(intent); | ||
| + | |||
| + | Bundle extras = intent.getExtras(); | ||
| + | if (!extras.isEmpty()) { | ||
| + | // filter the message according to its type | ||
| + | if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) { | ||
| + | sendNotification(extras); | ||
| + | } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) { | ||
| + | sendNotification(extras); | ||
| + | } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) { | ||
| + | sendNotification(extras); | ||
| + | } | ||
| } | } | ||
| + | | ||
| + | // release the wake lock provided by the WakefulBroadcastReceiver. | ||
| + | GoogleCloudMessagingBroadcastReceiver.completeWakefulIntent(intent); | ||
| + | } | ||
| + | | ||
| + | // create a notification containing the message and post it | ||
| + | private void sendNotification(Bundle bundle) { | ||
| + | Intent notificationHandlerIntent = new Intent(this, NotificationHandlerActivity.class); | ||
| + | notificationHandlerIntent.putExtras(bundle); | ||
| + | | ||
| + | TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this); | ||
| + | taskStackBuilder.addParentStack(NotificationHandlerActivity.class); | ||
| + | taskStackBuilder.addNextIntent(notificationHandlerIntent); | ||
| + | | ||
| + | PendingIntent notificationHandlerPendingIntent = taskStackBuilder.getPendingIntent( | ||
| + | 0, | ||
| + | PendingIntent.FLAG_UPDATE_CURRENT); | ||
| + | | ||
| + | NotificationCompat.Builder builder = new NotificationCompat.Builder(this) | ||
| + | .setSmallIcon(R.drawable.ic_launcher) | ||
| + | .setContentTitle(Constants.TAG) | ||
| + | .setStyle(new NotificationCompat.BigTextStyle().bigText(Constants.NOTIFICATION_MESSAGE)) | ||
| + | .setContentText(Constants.NOTIFICATION_MESSAGE); | ||
| + | | ||
| + | builder.setContentIntent(notificationHandlerPendingIntent); | ||
| + | | ||
| + | NotificationManager notificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE); | ||
| + | notificationManager.notify(Constants.NOTIFICATION_ID, builder.build()); | ||
| + | } | ||
| + | } | ||
| + | </file> | ||
| - | @Override | ||
| - | protected void onHandleIntent(Intent intent) { | ||
| - | // the intent is supplied via the BroadcastReceiver | ||
| - | |||
| - | GoogleCloudMessaging googleCloudMessaging = GoogleCloudMessaging.getInstance(this); | ||
| - | |||
| - | Bundle extras = intent.getExtras(); | ||
| - | if (!extras.isEmpty()) { | ||
| - | String messageType = googleCloudMessaging.getMessageType(intent); | ||
| - | // filter the message according to its type | ||
| - | // send a notification containing the data attached to the message (as extras) | ||
| - | if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) { | ||
| - | sendNotification("Send error: " + extras.toString()); | ||
| - | } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) { | ||
| - | sendNotification("Deleted messages on server: " + extras.toString()); | ||
| - | } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) { | ||
| - | sendNotification("Received: " + extras.toString()); | ||
| - | } | ||
| - | } | ||
| - | // release the wake lock provided by the WakefulBroadcastReceiver. | ||
| - | GoogleCloudMessagingBroadcastReceiver.completeWakefulIntent(intent); | ||
| - | } | ||
| - | |||
| - | // create a notification containing the message and post it | ||
| - | private void sendNotification(String message) { | ||
| - | // ... | ||
| - | } | ||
| - | } | ||
| - | </code> | ||
| ==== Permisiuni AndroidManifest.xml ==== | ==== Permisiuni AndroidManifest.xml ==== | ||
| Line 446: | Line 447: | ||
| </code> | </code> | ||
| * în fișierul ''AndroidManifest.xml'' se precizează permisiunile necesare pentru ca aplicația să poată utiliza funcționalitățile oferite de Google Cloud Messaging\\ <code xml> | * în fișierul ''AndroidManifest.xml'' se precizează permisiunile necesare pentru ca aplicația să poată utiliza funcționalitățile oferite de Google Cloud Messaging\\ <code xml> | ||
| - | <manifest package="ro.pub.systems.pdsd.lab09.GoogleCloudMessagingClient" ...> | + | <manifest package="ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging" ...> |
| - | <uses-permission android:name="android.permission.INTERNET" /> | + | <uses-permission |
| - | <uses-permission android:name="android.permission.GET_ACCOUNTS" /> | + | android:name="android.permission.INTERNET" /> |
| - | <uses-permission android:name="android.permission.WAKE_LOCK" /> | + | <uses-permission |
| - | <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> | + | android:name="android.permission.GET_ACCOUNTS" /> |
| + | <uses-permission | ||
| + | android:name="android.permission.WAKE_LOCK" /> | ||
| + | <uses-permission | ||
| + | android:name="com.google.android.c2dm.permission.RECEIVE" /> | ||
| - | <permission android:name="ro.pub.systems.pdsd.lab09.GoogleCloudMessagingClient.permission.C2D_MESSAGE" | + | <permission |
| - | android:protectionLevel="signature" /> | + | android:name="ro.pub.systems.pdsd.lab08.googlecloudmessaging.permission.C2D_MESSAGE" |
| - | <uses-permission android:name="ro.pub.systems.pdsd.lab09.GoogleCloudMessagingClient.permission.C2D_MESSAGE" /> | + | android:protectionLevel="signature" /> |
| - | + | <uses-permission | |
| - | <application ...> | + | android:name="ro.pub.systems.pdsd.lab08.googlecloudmessaging.permission.C2D_MESSAGE" /> |
| - | <receiver | + | |
| - | android:name=".GoogleCloudMessagingBroadcastReceiver" | + | |
| - | android:permission="com.google.android.c2dm.permission.SEND" > | + | |
| - | <intent-filter> | + | |
| - | <action android:name="com.google.android.c2dm.intent.RECEIVE" /> | + | |
| - | <category android:name="ro.pub.systems.pdsd.lab09.GoogleCloudMessagingClient" /> | + | |
| - | </intent-filter> | + | |
| - | </receiver> | + | |
| - | <service android:name=".GoogleCloudMessagingIntentService" /> | + | |
| - | </application> | + | |
| + | <application ...> | ||
| + | <meta-data | ||
| + | android:name="com.google.android.gms.version" | ||
| + | android:value="@integer/google_play_services_version" /> | ||
| + | <activity | ||
| + | android:name="ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.view.GoogleCloudMessagingActivity" | ||
| + | android:label="@string/app_name" > | ||
| + | <intent-filter> | ||
| + | <action android:name="android.intent.action.MAIN" /> | ||
| + | <category android:name="android.intent.category.LAUNCHER" /> | ||
| + | </intent-filter> | ||
| + | </activity> | ||
| + | <activity | ||
| + | android:name="ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.view.NotificationHandlerActivity" | ||
| + | android:parentActivityName="ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.view.GoogleCloudMessagingActivity"> | ||
| + | <meta-data | ||
| + | android:name="android.support.PARENT_ACTIVITY" | ||
| + | android:value="ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.view.GoogleCloudMessagingActivity" /> | ||
| + | </activity> | ||
| + | <receiver | ||
| + | android:name="ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.controller.GoogleCloudMessagingBroadcastReceiver" | ||
| + | android:permission="com.google.android.c2dm.permission.SEND" > | ||
| + | <intent-filter> | ||
| + | <action android:name="com.google.android.c2dm.intent.RECEIVE" /> | ||
| + | <category android:name="ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.controller.GoogleCloudMessagingBroadcastReceiver" /> | ||
| + | </intent-filter> | ||
| + | </receiver> | ||
| + | <service android:name="ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.controller.GoogleCloudMessagingIntentService" /> | ||
| + | </application> | ||
| </manifest> | </manifest> | ||
| </code> | </code> | ||
| + | |||
| <note important>Pentru a se asigura faptul că aplicația Android va rula corespunzător, ținând cont de faptul că Google Cloud Messaging nu poate fi folosit pe dispozitive mobile rulând un sistem de operare Android anterior versiunii 2.3, proprietatea ''android:minSdkVersion'' va avea o valoare egală sau mai mare cu 8.</note> | <note important>Pentru a se asigura faptul că aplicația Android va rula corespunzător, ținând cont de faptul că Google Cloud Messaging nu poate fi folosit pe dispozitive mobile rulând un sistem de operare Android anterior versiunii 2.3, proprietatea ''android:minSdkVersion'' va avea o valoare egală sau mai mare cu 8.</note> | ||
| - | * permisiunea ''android.permission.INTERNET'' este necesară pentru ca aplicația să poate transmite identificatorul său serverului de aplicații, prin intermediul căruia se realizează înregistrarea sa | + | * permisiunea ''android.permission.INTERNET'' este necesară pentru ca aplicația să poate transmite identificatorul său serverului de aplicații, prin intermediul căruia se realizează înregistrarea sa; |
| - | * permisiunea ''android.permission.GET_ACCOUNTS'' este necesară întrucât Google Cloud Messaging solicită (pentru sisteme de operare Android anterioare versiunii 4.0.4) un cont Google | + | * permisiunea ''android.permission.GET_ACCOUNTS'' este necesară întrucât Google Cloud Messaging solicită (pentru sisteme de operare Android anterioare versiunii 4.0.4) un cont Google; |
| - | * permisiunea ''android.permission.WAKE_LOCK'' (opțională) este necesară pentru a se preveni întreruperea activității în momentul în care este primit un mesaj | + | * permisiunea ''android.permission.WAKE_LOCK'' (opțională) este necesară pentru a se preveni întreruperea activității în momentul în care este primit un mesaj; |
| - | * permisiunea ''android.permission.RECEIVE'' este necesară pentru ca aplicația să se poată înregistra (în cadrul serverului de aplicații) și pentru a putea primi mesaje | + | * permisiunea ''android.permission.RECEIVE'' este necesară pentru ca aplicația să se poată înregistra (în cadrul serverului de aplicații) și pentru a putea primi mesaje; |
| - | * permisiunea de tip ''permission.C2D_MESSAGE'' (prefixată de denumirea pachetului care identifică în mod unic aplicația) pentru a preveni altă aplicație Android să se înregistreze (în cadrul serverului de aplicații) și să primească mesajele care îi sunt destinate | + | * permisiunea de tip ''permission.C2D_MESSAGE'' (prefixată de denumirea pachetului care identifică în mod unic aplicația) pentru a preveni altă aplicație Android să se înregistreze (în cadrul serverului de aplicații) și să primească mesajele care îi sunt destinate; |
| <note warning>Este necesar ca acest tip de permisiune să utilizeze această sintaxă, în caz contrar mesajele nefiind transmise aplicației Android.</note> | <note warning>Este necesar ca acest tip de permisiune să utilizeze această sintaxă, în caz contrar mesajele nefiind transmise aplicației Android.</note> | ||
| * un **ascultător** (de tipul ''com.google.android.c2dm.intent.RECEIVE'') având permisiunea ''com.google.android.c2dm.SEND'' astfel încât doar motorul Google Cloud Messaging să îi poată transmite mesaje | * un **ascultător** (de tipul ''com.google.android.c2dm.intent.RECEIVE'') având permisiunea ''com.google.android.c2dm.SEND'' astfel încât doar motorul Google Cloud Messaging să îi poată transmite mesaje | ||
| Line 488: | Line 513: | ||
| Se precizează regulile pentru obfuscatorul Proguard (în fișierul ''proguard-project.txt'' din rădăcina proiectului), astfel încât acesta să nu elimine clasele necesare:\\ <code java> | Se precizează regulile pentru obfuscatorul Proguard (în fișierul ''proguard-project.txt'' din rădăcina proiectului), astfel încât acesta să nu elimine clasele necesare:\\ <code java> | ||
| -keep class * extends java.util.ListResourceBundle { | -keep class * extends java.util.ListResourceBundle { | ||
| - | protected Object[][] getContents(); | + | protected Object[][] getContents(); |
| } | } | ||
| -keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable { | -keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable { | ||
| - | public static final *** NULL; | + | public static final *** NULL; |
| } | } | ||
| -keepnames @com.google.android.gms.common.annotation.KeepName class * | -keepnames @com.google.android.gms.common.annotation.KeepName class * | ||
| -keepclassmembernames class * { | -keepclassmembernames class * { | ||
| - | @com.google.android.gms.common.annotation.KeepName *; | + | @com.google.android.gms.common.annotation.KeepName *; |
| } | } | ||
| -keepnames class * implements android.os.Parcelable { | -keepnames class * implements android.os.Parcelable { | ||
| - | public static final ** CREATOR; | + | public static final ** CREATOR; |
| } | } | ||
| </code> | </code> | ||
| - | ===== Proiectarea și dezvoltarea serverului ===== | + | ===== Proiectarea și dezvoltarea serverului (opțional) ===== |
| Arhitectura Google Cloud Messaging implică existența a două servere: | Arhitectura Google Cloud Messaging implică existența a două servere: | ||
| Line 550: | Line 575: | ||
| // to which the application server sends a POST request in order to be further transmitted to the mobile device | // to which the application server sends a POST request in order to be further transmitted to the mobile device | ||
| - | final public static String REQUEST_SERVER_URL = "https://android.googleapis.com/gcm/send"; | + | final public static String GCM_SERVER_ADDRESS = "https://android.googleapis.com/gcm/send"; |
| // ... | // ... | ||
| - | HttpPost httpRequest = new HttpPost(REQUEST_SERVER_URL); | + | HttpPost httpRequest = new HttpPost(GCM_SERVER_ADDRESS); |
| </code> | </code> | ||
| Line 611: | Line 636: | ||
| * (for each mobile device to which the message is to be transmitted the message must specify | * (for each mobile device to which the message is to be transmitted the message must specify | ||
| * the id provided by the GCM server during the registration process) | * the id provided by the GCM server during the registration process) | ||
| - | * | + | * |
| * -> data contains the payload to be transmitted; the developer may define its own keys | * -> data contains the payload to be transmitted; the developer may define its own keys | ||
| * | * | ||
| Line 623: | Line 648: | ||
| JSONArray registrationIds = new JSONArray(); | JSONArray registrationIds = new JSONArray(); | ||
| registrationIds.add(registrationId); | registrationIds.add(registrationId); | ||
| - | requestBody.put("registration_ids", registrationIds); | + | requestBody.put(Constants.REGISTRATION_IDS, registrationIds); |
| JSONObject payload = new JSONObject(); | JSONObject payload = new JSONObject(); | ||
| - | payload.put("message", message); | + | payload.put(Constants.MESSAGE, message); |
| - | requestBody.put("data", payload); | + | requestBody.put(Constants.DATA, payload); |
| </code> | </code> | ||
| Line 639: | Line 664: | ||
| "registration_ids": ["..."], | "registration_ids": ["..."], | ||
| "data": { | "data": { | ||
| - | "message": "..." | + | "message": "..." |
| } | } | ||
| } | } | ||
| Line 647: | Line 672: | ||
| <code java> | <code java> | ||
| - | HttpClient client = HttpClientBuilder.create().build(); | + | CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); |
| // ... | // ... | ||
| Line 654: | Line 679: | ||
| // send the request | // send the request | ||
| - | HttpResponse httpResponse = client.execute(httpRequest); | + | HttpResponse httpResponse = httpClient.execute(httpRequest); |
| </code> | </code> | ||
| Line 690: | Line 715: | ||
| <code> | <code> | ||
| if (firstLine.startsWith("id")) { | if (firstLine.startsWith("id")) { | ||
| - | if (secondLine.equals("registration_id")) { | + | if (secondLine.equals("registration_id")) { |
| - | old_registration_id = get registration_id from the request field | + | old_registration_id = get registration_id from the request field |
| - | replace old_registration_id with new registration_id in the request / application server database | + | replace old_registration_id with new registration_id in the request / application server database |
| - | } | + | } |
| } else { | } else { | ||
| - | switch(Error) { | + | switch(Error) { |
| - | case "NotRegistered": | + | case "NotRegistered": |
| - | // the application was uninstalled from the device | + | // the application was uninstalled from the device |
| - | // or it does not have a broadcast receiver in order to process com.google.android.c2dm.intent.RECEIVE intents | + | // or it does not have a broadcast receiver in order to process com.google.android.c2dm.intent.RECEIVE intents |
| - | remove the registration ID from the application server database | + | remove the registration ID from the application server database |
| - | break; | + | break; |
| - | default: | + | default: |
| - | // non-recoverable error regarding the registration ID | + | // non-recoverable error regarding the registration ID |
| - | remove the registration ID from the application server database | + | remove the registration ID from the application server database |
| - | break; | + | break; |
| - | } | + | } |
| } | } | ||
| </code> | </code> | ||
| Line 722: | Line 747: | ||
| <code> | <code> | ||
| if (failure != 0 && canonical_ids != 0) { | if (failure != 0 && canonical_ids != 0) { | ||
| - | for-each (result ∈ results) { | + | for-each (result ∈ results) { |
| - | if (result.registration_id) { | + | if (result.registration_id) { |
| - | // the old registration ID is not included within the response | + | // the old registration ID is not included within the response |
| - | old_registration_id = get registration_id from the request field registration_ids, having the same index | + | old_registration_id = get registration_id from the request field registration_ids, having the same index |
| | | ||
| - | replace old_registration_id with new result.registration_id in the request | + | replace old_registration_id with new result.registration_id in the request |
| - | } else { | + | } else { |
| - | switch(error) { | + | switch(error) { |
| - | case "Unavailable": | + | case "Unavailable": |
| - | retry sending the request | + | retry sending the request |
| - | break; | + | break; |
| - | case "NotRegistered": | + | case "NotRegistered": |
| - | // the application was uninstalled from the device | + | // the application was uninstalled from the device |
| - | // or it does not have a broadcast receiver in order to process com.google.android.c2dm.intent.RECEIVE intents | + | // or it does not have a broadcast receiver in order to process com.google.android.c2dm.intent.RECEIVE intents |
| - | remove the registration ID from the application server database | + | remove the registration ID from the application server database |
| - | break; | + | break; |
| - | default: | + | default: |
| - | // non-recoverable error regarding the registration ID | + | // non-recoverable error regarding the registration ID |
| - | remove the registration ID from the application server database | + | remove the registration ID from the application server database |
| - | break; | + | break; |
| - | } | + | } |
| - | } | + | |
| } | } | ||
| + | } | ||
| } | } | ||
| </code> | </code> | ||
| Line 789: | Line 814: | ||
| @Override | @Override | ||
| public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | ||
| - | Enumeration<String> parameters = request.getParameterNames(); | + | Enumeration<String> parameters = request.getParameterNames(); |
| - | boolean found = false; | + | |
| - | while(parameters.hasMoreElements()) { | + | String registrationId = null; |
| - | String parameter = (String)parameters.nextElement(); | + | String username = null; |
| - | if (parameter.equals(Constants.REGISTRATION_ID)) { | + | String email = null; |
| - | found = true; | + | |
| - | registrationId = request.getParameter(parameter); | + | while (parameters.hasMoreElements()) { |
| - | } | + | String parameter = (String)parameters.nextElement(); |
| - | if (parameter.equals(Constants.USER_NAME)) { | + | if (parameter.equals(Constants.REGISTRATION_ID)) { |
| - | userName = request.getParameter(parameter); | + | registrationId = request.getParameter(parameter); |
| - | } | + | } |
| - | if (parameter.equals(Constants.EMAIL)) { | + | if (parameter.equals(Constants.USERNAME)) { |
| - | email = request.getParameter(parameter); | + | username = request.getParameter(parameter); |
| - | } | + | } |
| - | } | + | if (parameter.equals(Constants.EMAIL)) { |
| - | if (found) { | + | email = request.getParameter(parameter); |
| - | ArrayList<String> values = new ArrayList<String>(); | + | } |
| - | values.add(registrationId); | + | } |
| - | values.add(userName); | + | |
| - | values.add(email); | + | if (registrationId != null && !registrationId.isEmpty() && |
| - | values.add(general.Constants.SYSTEM_FUNCTION[0]); | + | username != null && !username.isEmpty() && |
| - | try { | + | email != null && !email.isEmpty()) { |
| - | DataBaseConnection.insertValuesIntoTable(Constants.TABLE_NAME, null, values, true); | + | ArrayList<String> columnNames = new ArrayList<String>(); |
| - | } catch (Exception exception) { | + | columnNames.add(Constants.REGISTRATION_ID); |
| - | System.out.println("exceptie: "+exception.getMessage()); | + | columnNames.add(Constants.USERNAME); |
| - | if (Constants.DEBUG) | + | columnNames.add(Constants.EMAIL); |
| - | exception.printStackTrace(); | + | ArrayList<String> values = new ArrayList<String>(); |
| - | } | + | values.add(registrationId); |
| - | } | + | values.add(username); |
| - | response.setContentType("text/html"); | + | values.add(email); |
| - | try { | + | |
| - | PrintWriter printWriter = new PrintWriter(response.getWriter()); | + | try { |
| - | ArrayList<ArrayList<Object>> records = DataBaseConnection.getTableContent(Constants.TABLE_NAME, null, null, null, null); | + | dataBaseWrapper.insertValuesIntoTable(Constants.TABLE_NAME, columnNames, values, false); |
| - | GoogleCloudMessagingGraphicUserInterface.displayGoogleCloudMessagingGraphicUserInterface(records, printWriter); | + | } catch (SQLException | DataBaseException exception) { |
| - | } catch (Exception exception) { | + | System.out.println("An exception has occurred: "+exception.getMessage()); |
| - | System.out.println("exceptie: "+exception.getMessage()); | + | if (Constants.DEBUG) { |
| - | if (Constants.DEBUG) | + | exception.printStackTrace(); |
| - | exception.printStackTrace(); | + | } |
| - | response.setStatus(HttpServletResponse.SC_BAD_REQUEST); | + | } |
| - | } | + | response.setStatus(HttpServletResponse.SC_OK); |
| - | response.setStatus(HttpServletResponse.SC_OK); | + | } else { |
| + | response.setStatus(HttpServletResponse.SC_BAD_REQUEST); | ||
| + | } | ||
| } | } | ||
| </code> | </code> | ||
| Line 835: | Line 862: | ||
| Se observă faptul că se prelucrează cererea de tip POST, iterându-se pe toți parametrii incluși în scopul identificării valorilor asociate atributelor denumite nume de utilizator, adresă de poștă electronică și identificator de înregistrare (conform protocolului de comunicație definit de utilizator), aceștia fiind stocați în baza de date locală pentru a fi utilizați în transmiterea ulterioară a unui mesaj. | Se observă faptul că se prelucrează cererea de tip POST, iterându-se pe toți parametrii incluși în scopul identificării valorilor asociate atributelor denumite nume de utilizator, adresă de poștă electronică și identificator de înregistrare (conform protocolului de comunicație definit de utilizator), aceștia fiind stocați în baza de date locală pentru a fi utilizați în transmiterea ulterioară a unui mesaj. | ||
| - | <note important>Este foarte important să fie specificată o stare în cadrul răspunsului (prin apelul metodei ''setStatus'' a obiectului ''HttpServletResponse'') desemnând rezultatul procesării mesajului, în caz contrar clientul Android blocându-se până la expirarea perioadei de timp pentru așteptare (//eng.// timeout).</note> | + | <note important>Este foarte important să fie specificată o stare în cadrul răspunsului (prin apelul metodei ''setStatus()'' a obiectului ''HttpServletResponse'') desemnând rezultatul procesării mesajului, în caz contrar clientul Android blocându-se până la expirarea perioadei de timp pentru așteptare (//eng.// timeout).</note> |
| ===== Activitate de Laborator ===== | ===== Activitate de Laborator ===== | ||
| Line 843: | Line 871: | ||
| * se generează o cheie publică pentru transmiterea de mesaje provenind de la un server, indiferent de adresa Internet la care se găsește acesta. | * se generează o cheie publică pentru transmiterea de mesaje provenind de la un server, indiferent de adresa Internet la care se găsește acesta. | ||
| - | Mai multe detalii pot fi obținute în secțiunea [[:laboratoare:laborator09#configurare|Configurare]]. | + | Mai multe detalii pot fi obținute în secțiunea [[:laboratoare:laborator08#configurare|Configurare]]. |
| <note>În cazul în care nu dispuneți de un cont Google, acesta va trebui creat înainte de a implementa aceste cerințe.</note> | <note>În cazul în care nu dispuneți de un cont Google, acesta va trebui creat înainte de a implementa aceste cerințe.</note> | ||
| + | |||
| + | <note important>Aceste valori nu vor fi utilizate decât împreună, altfel se vor genera erori de tipul ''MismatchSenderId''.</note> | ||
| ==== Clientul Android ==== | ==== Clientul Android ==== | ||
| - | **2.** Să se configureze clientul pentru a putea rula o aplicație Android folosind Google Cloud Messaging: | + | **2.** În contul Github personal, să se creeze un depozit denumit 'Laborator08-Client'. Inițial, acesta trebuie să fie gol (nu trebuie să bifați nici adăugarea unui fișier ''README.md'', nici a fișierului ''.gitignore'' sau a a fișierului ''LICENSE''). |
| - | * se instalează SDK-ul Google Cloud Messaging | + | |
| - | * se configurează mașina pe care va rula aplicația | + | |
| - | * în cazul în care se utilizează un emulator, se configurează astfel încât acesta să aibă instalat Google Play Services | + | |
| - | * în cazul în care se utilizează un dispozitiv fizic, acesta trebuie să ruleze un sistem de operare Android cu o versiune ulterioară 2.2, având asociat un cont Google | + | |
| - | Mai multe detalii pot fi obținute în secțiunea [[:laboratoare:laborator09#configurare_client|Configurare client]] | + | **3.** Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la [[https://www.github.com/pdsd2015/Laborator08-Client|]]. |
| - | **3.** În mediul de dezvoltare să se deschidă proiectele ''google-play-services_lib'' (acesta ar trebui să se găsească și la ''<android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib'' după ce a fost instalat SDK-ul Google Cloud Messaging) și ''GoogleCloudMessagingClient''. | + | În urma acestei operații, directorul Laborator08-Client va trebui să se conțină directoarele ''labtasks'' și ''solutions''. |
| - | **4.** În interfața ''ro.pub.systems.pdsd.lab09.googlecloudmessagingclient.Configuration'', trebuie modificate următoarele valori: | + | <code> |
| + | student@pdsd2015:~$ git clone https://www.github.com/pdsd2015/Laborator08-Client | ||
| + | </code> | ||
| + | |||
| + | **4.** Să se încarce conținutul descărcat în cadrul depozitului 'Laborator08-Client' de pe contul Github personal. <code> | ||
| + | student@pdsd2015:~$ cd Laborator08-Client | ||
| + | student@pdsd2015:~/Laborator08-Client$ git remote add Laborator08-Client_perfectstudent https://github.com/perfectstudent/Laborator08-Client | ||
| + | student@pdsd2015:~/Laborator08-Client$ git push Laborator08-Client_perfectstudent master | ||
| + | </code> | ||
| + | |||
| + | **5.** Să se importe în mediul integrat de dezvoltare Eclipse Luna SR1a (4.4.1) proiectele ''google-play-service_lib'' și ''GoogleCloudMessagingClient'' din directorul ''labtasks'' (în această ordine). | ||
| + | |||
| + | Să se configureaze mașina pe care va rula aplicația: | ||
| + | * în cazul în care se utilizează un emulator, se configurează astfel încât acesta să aibă instalat Google Play Services; | ||
| + | * în cazul în care se utilizează un dispozitiv fizic, acesta trebuie să ruleze un sistem de operare Android cu o versiune ulterioară 2.2, având asociat un cont Google. | ||
| + | |||
| + | <note>În situația în care nu se reușește configurarea unui dispozitiv virtual, se poate folosi [[http://pdsd2015.andreirosucojocaru.ro/resources/Genymobile.tar.gz|o imagine Nexus S (API 16)]] care trebuie plasată în directorul ''$HOME''.</note> | ||
| + | |||
| + | Mai multe detalii pot fi obținute în secțiunea [[:laboratoare:laborator08#configurare_client|Configurare client]] | ||
| + | |||
| + | **6.** În interfața ''ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.general.Constants'', trebuie modificate următoarele valori, __**numai în situația în care se folosește un server web Apache Tomcat**__: | ||
| * ''PROJECT_NUMBER'' - cu numărul de proiect generat de consola Google API; | * ''PROJECT_NUMBER'' - cu numărul de proiect generat de consola Google API; | ||
| - | * ''GOOGLECLOUDMESSAGING_WEBSERVER_URL'' - cu adresa Internet la care rulează serverul de aplicații | + | * adresele Internet pentru serviciile care expun funcționalități către dispozitivul mobil: |
| - | * dispozitiv mobil - adresa Internet indicată ca default gateway a rețelei de calculatoare din care fac parte dispozitivul mobil și mașina pe care se găsește serverul de aplicații | + | * dispozitiv mobil - adresa Internet indicată ca default gateway a rețelei de calculatoare din care fac parte dispozitivul mobil și mașina pe care se găsește serverul de aplicații; |
| - | * AVD - 10.0.2.1 | + | * AVD - 10.0.2.1; |
| - | * Genymotion - 192.168.56.1 | + | * Genymotion - 192.168.56.1. |
| - | <note tip>Portul pe care rulează serverul web Apache Tomcat este de regulă 8080 (dacă nu s-au realizat alte modificări în fișierul de configurare ''server.xml'').</note> | + | <note tip>Portul pe care rulează serverul web Apache Tomcat este de regulă 8080 (dacă nu s-au realizat alte modificări în fișierul de configurare ''server.xml''). În situația în care, în momentul în care se încearcă să se realizeze conexiunea la serverul de aplicații, se obține o excepție de tip //Timeout// / //Connection Refused//, investigați dacă este permisă comunicația pe portul respectiv.</note> |
| - | **5.** Să se ruleze aplicația Android și să se genereze identificatorul de înregistrare, care va fi transmis prin accesarea butonului ''Send'' de îndată ce serverul de aplicații devine disponibil. | + | **7.** Să se ruleze aplicația Android și să se genereze identificatorul de înregistrare, care va fi transmis către serverul de aplicații prin accesarea butonului ''Send Registration ID''. |
| - | ==== Serverul de Aplicații ==== | + | {{ :laboratoare:laborator08:mobile_device_application01.png?nolink&400 }} |
| - | <note tip>Informații referitoare la configurarea serverului de aplicații pot fi obținute la [[:laboratoare:laborator09#configurare_server|Configurare Server]].</note> | + | {{ :laboratoare:laborator08:mobile_device_application02.png?nolink&400 }} |
| - | **6.** Să se descarce cea mai recentă versiune stabilă a serverului web Apache Tomcat și să se dezarhiveze. | + | În fragmentul ''UnregisteredFragment'' din pachetul ''ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.view'', pe clasa ascultător asociată butonului, să se transmită o cerere HTTP de tip POST către componenta din serverul de aplicații, responsbilă cu înregistrarea dispozitivelor mobile (disponibilă la ''Constants.DEVICE_REGISTRATION_SERVICE_ADDRESS''). |
| - | **7.** Să se descarce cea mai recentă versiune stabilă a mediului de dezvoltare Eclipse IDE for Java EE Developers, integrându-se cu serverul web Apache Tomcat. | + | Aceasta va conține următorii parametrii: |
| + | * ''Constants.USERNAME'' - numele de utilizator din câmpul text; | ||
| + | * ''Constants.EMAIL'' - adresa de poștă electronică din câmpul text; | ||
| + | * ''Constants.REGISTRATION_ID'' - identificatorul de înregistrare furnizat de serviciul Google Cloud Messaging. | ||
| - | **8.** Să se instaleze motorul pentru gestiunea bazelor de date MySQL și să se ruleze script-ul ''Laborator09.sql'' din cadrul proiectului ''GoogleCloudMessagingWebServer'' care creează o bază de date cu o tabelă în care vor fi stocate informațiile referitoare la identificatorii de înregistrare transmiși de clienții Android. | + | Codificarea utilizată pentru această comunicație este UTF-8. |
| - | <code sql> | + | În situația în care codul întors pe linia de stare în răspuns este 200, se va întoarce rezultatul ''Constants.SUCCESS''. |
| + | |||
| + | **8.** În situația în care înregistrarea a fost realizată cu succes, interfața grafică a aplicației este modificată în sensul în care se dorește afișarea unei liste cu utilizatorii care au fost înregistrați deja, către care se dorește transmiterea unui mesaj de notificare. | ||
| + | |||
| + | {{ :laboratoare:laborator08:mobile_device_application03.png?nolink&400 }} | ||
| + | |||
| + | **a)** Pe firul de execuție ''RegisteredDevicesFetcher'' din fragmentul ''RegisteredFragment'', să se transmită o cerere HTTP de tip GET către către componenta din serverul de aplicații, responsbilă cu furnizarea listei dispozitivelor mobile înregistrate, în format JSON (disponibilă la ''Constants.REGISTERED_DEVICES_SERVICE_ADDRESS''). | ||
| + | |||
| + | Să se prelucreze documentul JSON obținut, astfel încât prin intermediul acestuia să se populeze un tablou de obiecte ''RegisteredDevice'', transmis ca parametru adaptorului obiectului de tip ''Spinner'' în care pot fi vizualizate astfel de informații. | ||
| + | |||
| + | <code java> | ||
| + | final ArrayList<RegisteredDevice> registeredDevices = new ArrayList<RegisteredDevice>(); | ||
| + | // ... | ||
| + | registeredDevicesSpinner.post(new Runnable() { | ||
| + | @Override | ||
| + | public void run() { | ||
| + | RegisteredDevicesAdapter registeredDevicesAdapter = new RegisteredDevicesAdapter(getActivity(), registeredDevices); | ||
| + | registeredDevicesSpinner.setAdapter(registeredDevicesAdapter); | ||
| + | } | ||
| + | }); | ||
| + | </code> | ||
| + | |||
| + | Documentul JSON conține informații despre identificatorul din baza de date, identificatorul de înregistrare furnizat de serverul GoogleCloudMessaging, numele de utilizator, adresa de poștă electronică și momentul de timp la care a fost realizată înregistratrea. | ||
| + | |||
| + | <code json> | ||
| + | [ | ||
| + | { | ||
| + | "id": ..., | ||
| + | "registration_id": "...", | ||
| + | "username": "...", | ||
| + | "email": "...", | ||
| + | "timestamp": "...", | ||
| + | }, | ||
| + | ... | ||
| + | ] | ||
| + | </code> | ||
| + | |||
| + | ^ atribut JSON ^ tip de date ^ detaliu ^ | ||
| + | | ''Constants.ID'' | ''int'' | identificator în baza de date | | ||
| + | | ''Constants.REGISTRATION_ID'' | ''String'' | identificator de înregistrare furnizat de serverul Google Cloud Messaging | | ||
| + | | ''Constants.USERNAME'' | ''String'' | numele de utilizator | | ||
| + | | ''Constants.EMAIL'' | ''String'' | adresa de poștă electonică | | ||
| + | | ''Constants.TIMESTAMP'' | ''String'' | momentul de timp la care a fost realizată înregistrarea | | ||
| + | |||
| + | **b)** Pe firul de execuție ''MessagePushExecutor'' din fragmentul ''RegisteredFragment'', să se transmită o cerere HTTP de tip POST către către componenta din serverul de aplicații, responsbilă cu transmiterea unui mesaj sub forma unei notificări (disponibilă la ''Constants.MESSAGE_PUSH_SERVICE_ADDRESS''). | ||
| + | |||
| + | Aceasta va conține următorii parametrii (instanțiați ca membrii ai clasei): | ||
| + | * ''Constants.REGISTRATION_ID'' - identificatorul de înregistrare furnizat de serverul Google Cloud Messaging; | ||
| + | * ''Constants.MESSAGE'' - mesajul propriu-zis care se dorește a fi transmis. | ||
| + | |||
| + | Codificarea utilizată pentru această comunicație este UTF-8. | ||
| + | |||
| + | În această situație, nu este necesară prelucrarea rezultatului obținut. | ||
| + | |||
| + | **9.** În momentul în care este transmis un mesaj de către expeditor, să se observe notificarea destinatarului și activitatea în care pot fi vizualizați parametrii pachetului furnizat de serverul Google Cloud Messaging. | ||
| + | |||
| + | {{ :laboratoare:laborator08:mobile_device_application04.png?nolink&400 }} | ||
| + | |||
| + | **10.** Să se încarce modificările realizate în cadrul depozitului 'Laborator08-Client' de pe contul Github personal, folosind un mesaj sugestiv. <code> | ||
| + | student@pdsd2015:~/Laborator08-Client$ git add * | ||
| + | student@pdsd2015:~/Laborator08-Client$ git commit -m "implemented taks for laboratory 08-Client" | ||
| + | student@pdsd2015:~/Laborator08-Client$ git push Laborator08-Client_perfectstudent master | ||
| + | </code> | ||
| + | |||
| + | ==== Serverul de Aplicații (Opțional) ==== | ||
| + | |||
| + | <note tip>Informații referitoare la configurarea serverului de aplicații pot fi obținute la [[:laboratoare:laborator08#configurare_server_optional|Configurare Server]].</note> | ||
| + | |||
| + | Funcționalitatea corespunzătoare serverului de aplicații este disponibilă în două variante: | ||
| + | * PHP & MySQL, găzduită la o adresă Internet publică; | ||
| + | * JavaServlets / JSP & MySQL (folosind un server web Apache Tomcat 8.0.21 - integrat în structura proiectului, fără a necesita configurare), care poate fi rulat pe mașina fizică (local), comunicând cu dispozitivul mobil numai în situația în care acestea se găsesc în aceeași rețea și portul 8080 nu este blocat - de aceea, toate operațiile de configurare ce urmează se referă la această aplicație. | ||
| + | |||
| + | Pe serverul de aplicații sunt disponibile următoarele funcționalități, în cadrul unor componente diferite: | ||
| + | * înregistrarea unui dispozitiv mobil în cadrul unei baze de date locale, pe baza unui identificator de înregistrare furnizat de serverul Google Cloud Messaging; | ||
| + | * listarea tuturor dispozitivelor mobile înregistrate sub forma unui document JSON; | ||
| + | * transmiterea unui mesaj sub forma unui notificări către un dispozitiv mobil, prin intermediul serverului Google Cloud Messaging. | ||
| + | |||
| + | **11.** În contul Github personal, să se creeze un depozit denumit 'Laborator08-Server'. Inițial, acesta trebuie să fie gol (nu trebuie să bifați nici adăugarea unui fișier ''README.md'', nici a fișierului ''.gitignore'' sau a a fișierului ''LICENSE''). | ||
| + | |||
| + | **12.** Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la [[https://www.github.com/pdsd2015/Laborator08-Server|]]. | ||
| + | |||
| + | În urma acestei operații, directorul Laborator08-Server va trebui să se conțină directoarele ''PHP'' și ''ServletsJSP''. | ||
| + | |||
| + | <code> | ||
| + | student@pdsd2015:~$ git clone https://www.github.com/pdsd2015/Laborator08-Server | ||
| + | </code> | ||
| + | |||
| + | **13.** Să se încarce conținutul descărcat în cadrul depozitului 'Laborator08-Server' de pe contul Github personal. <code> | ||
| + | student@pdsd2015:~$ cd Laborator08-Server | ||
| + | student@pdsd2015:~/Laborator08-Server$ git remote add Laborator08-Server_perfectstudent https://github.com/perfectstudent/Laborator08-Server | ||
| + | student@pdsd2015:~/Laborator08-Server$ git push Laborator08-Server_perfectstudent master | ||
| + | </code> | ||
| + | |||
| + | **14.** Să se descarce cea mai recentă versiune stabilă a mediului de dezvoltare Eclipse IDE for Java EE Developers, integrându-se cu serverul web Apache Tomcat. | ||
| + | |||
| + | **15.** Să se instaleze motorul pentru gestiunea bazelor de date MySQL și să se ruleze script-ul ''googlecloudmessaging.sql'' din cadrul directorului ''ServletsJSP'' care creează o bază de date cu o tabelă în care vor fi stocate informațiile referitoare la identificatorii de înregistrare transmiși de clienții Android. | ||
| + | |||
| + | <code> | ||
| CREATE DATABASE googlecloudmessaging; | CREATE DATABASE googlecloudmessaging; | ||
| Line 886: | Line 1032: | ||
| CREATE TABLE registered_devices ( | CREATE TABLE registered_devices ( | ||
| - | id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, | + | id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, |
| - | registration_id TEXT NOT NULL, | + | registration_id TEXT NOT NULL, |
| - | username VARCHAR(255), | + | username VARCHAR(255), |
| - | email VARCHAR(255), | + | email VARCHAR(255), |
| - | creation_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP | + | timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP |
| ); | ); | ||
| </code> | </code> | ||
| Line 896: | Line 1042: | ||
| Rularea acestuia se poate realiza folosind una dintre următoarele variante, presupunând că vă aflați în directorul în care se găsește acest fișier: | Rularea acestuia se poate realiza folosind una dintre următoarele variante, presupunând că vă aflați în directorul în care se găsește acest fișier: | ||
| - <code> | - <code> | ||
| - | mysql -u root -p <Laborator09.sql | + | student@pdsd2015:~/Laborator08-Server/JSPServlets$ mysql -u root -p <googlecloudmessaging.sql |
| </code> | </code> | ||
| - <code> | - <code> | ||
| - | mysql -u root -p | + | student@pdsd2015:~/Laborator08-Server/JSPServlets$ mysql -u root -p |
| Enter password: | Enter password: | ||
| </code> | </code> | ||
| - <code> | - <code> | ||
| - | mysql> source Laborator09.sql; | + | mysql> source googlecloudmessaging.sql; |
| </code> sau | </code> sau | ||
| - <code> | - <code> | ||
| - | mysql> \. Laborator09.sql; | + | mysql> \. googlecloudmessaging.sql; |
| </code> | </code> | ||
| - | **9.** În mediul de dezvoltare Eclipse IDE for Java EE Developers să se deschidă proiectul ''GoogleCloudMessaging''. | + | **16.** Să se importe proiectul ''GoogleCloudMessagingServer'' în mediul de dezvoltare Eclipse IDE for Java EE Developers. |
| - | **10.** În interfața ''general.Constants'', trebuie modificate următoarele valori: | + | **17.** În interfața ''Constants'' din pachetul ''ro.pub.cs.systems.pdsd.lab08.googlecloudmessaging.general'', trebuie modificate următoarele valori: |
| * ''DATABASE_PASSWORD'' - parola de administrare a motorului pentru gestiunea bazei de date MySQL, care a fost introdusă la instalarea acestui produs; | * ''DATABASE_PASSWORD'' - parola de administrare a motorului pentru gestiunea bazei de date MySQL, care a fost introdusă la instalarea acestui produs; | ||
| * ''API_KEY'' - cheia publică de acces a serverului Google Cloud Messaging de către serverul de aplicații, așa cum a fost generată de Consola Google API. | * ''API_KEY'' - cheia publică de acces a serverului Google Cloud Messaging de către serverul de aplicații, așa cum a fost generată de Consola Google API. | ||
| - | ===== ===== | + | **18.** În acest moment, se poate realiza comunicația client Android ↔ server de aplicații prin intermediul serviciului Google Cloud Messaging: |
| - | + | * clientul Android trimite identificatorul de înregistrare către serverul de aplicații; | |
| - | **11.** În acest moment, se poate realiza comunicația client Android ↔ server de aplicații prin intermediul serviciului Google Cloud Messaging: | + | * se accesează componenta pentru transmiterea unui mesaj prin intermediul unei notificări în aplicația curentă de navigare (//eng.// browser)\\ {{ pdsd:laboratoare:laborator08:message_push.png?nolink&800 }} |
| - | * clientul Android trimite identificatorul de înregistrare către serverul de aplicații;\\ {{ :laboratoare:lab09-mobiledeviceunregistered.jpg?nolink }}\\ {{ :laboratoare:lab09-mobiledeviceregistered.jpg?nolink }} | + | * PHP: http://pdsd2015.andreirosucojocaru.ro/exemple/laboratoare/laborator08/googlecloudmessaging/message_push.php; |
| - | * se accesează servletul ''GoogleCloudMessagingRegisterServlet'' prin intermediul unei aplicații de navigare (//eng.// browser) pentru a se transmite un mesaj către dispozitivul mobil, acesta fiind afișat sub forma unei notificări.\\ {{ :laboratoare:lab09-GoogleCloudMessagingWebServer.jpg?nolink }} | + | * JavaServlets / JSP (local): http://192.168.56.1:8080/GoogleCloudMessagingServer/MessagePushServlet. |
| ===== Resurse Utile ===== | ===== Resurse Utile ===== | ||
| - | {{:laboratoare:client.zip|Surse Client}}\\ | ||
| - | {{:laboratoare:server.zip|Surse Server}} | ||
| - | |||
| [[http://tomcat.apache.org/download-70.cgi|Apache Tomcat 7 Downloads]]\\ | [[http://tomcat.apache.org/download-70.cgi|Apache Tomcat 7 Downloads]]\\ | ||
| [[http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/keplersr2|Eclipse IDE for Java EE Developers]]\\ | [[http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/keplersr2|Eclipse IDE for Java EE Developers]]\\ | ||
| Line 933: | Line 1076: | ||
| [[http://developer.android.com/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html|Google Cloud Messaging API]]\\ | [[http://developer.android.com/reference/com/google/android/gms/gcm/GoogleCloudMessaging.html|Google Cloud Messaging API]]\\ | ||
| [[http://stackoverflow.com/questions/20121883/how-to-install-google-play-services-in-a-genymotion-vm-with-no-drag-and-drop-su|How to install Google Play Services in a Genymotion VM (with no drag and drop support)?]]\\ | [[http://stackoverflow.com/questions/20121883/how-to-install-google-play-services-in-a-genymotion-vm-with-no-drag-and-drop-su|How to install Google Play Services in a Genymotion VM (with no drag and drop support)?]]\\ | ||
| - | [[http://wiki.cyanogenmod.org/w/Google_Apps|Google Apps]]\\ | + | [[http://forum.xda-developers.com/showthread.php?t=2528952|Installing ARM Translation and GApps]]\\ |
| - | [[http://forum.xda-developers.com/showthread.php?t=2528952|Installing ARM Translation and GApps]] | + | [[http://developer.android.com/guide/topics/ui/notifiers/notifications.html|Android Notifications]] |
