I am developing the GCM sample app using http://javapapers.com/android/google-cloud-messaging-gcm-for-android-and-push-notifications/#comment-103785.
I am unable to register gcm server.I am getting the following error.I have goggled it .but i couldn't find the solution and all the solutions were about jar files i have done all the changes but i couldn't get it.
Error
FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: com.google.android.gms.gcm.GoogleCloudMessaging
com.sanjeev.integrationapp.RegisterActivity.registerGCM(RegisterActivity.java:80)
com.sanjeev.integrationapp.RegisterActivity$1.onClick(RegisterActivity.java:47)
at android.view.View.performClick(View.java:4084)
at android.view.View$PerformClick.run(View.java:16966)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
And my class code follows
public class RegisterActivity extends Activity {
Button btnGCMRegister;
Button btnAppShare;
GoogleCloudMessaging gcm;
Context context;
String regId;
public static final String REG_ID = "regId";
private static final String APP_VERSION = "appVersion";
static final String TAG = "Register Activity";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
context = getApplicationContext();
btnGCMRegister = (Button) findViewById(R.id.btnGCMRegister);
btnGCMRegister.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
if (TextUtils.isEmpty(regId)) {
regId = registerGCM();
Log.d("RegisterActivity", "GCM RegId: " + regId);
} else {
Toast.makeText(getApplicationContext(),
"Already Registered with GCM Server!",
Toast.LENGTH_LONG).show();
}
}
});
btnAppShare = (Button) findViewById(R.id.btnAppShare);
btnAppShare.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
if (TextUtils.isEmpty(regId)) {
Toast.makeText(getApplicationContext(), "RegId is empty!",
Toast.LENGTH_LONG).show();
} else {
Intent i = new Intent(getApplicationContext(),
MainActivity.class);
i.putExtra("regId", regId);
Log.d("RegisterActivity",
"onClick of Share: Before starting main activity.");
startActivity(i);
finish();
Log.d("RegisterActivity", "onClick of Share: After finish.");
}
}
});
}
public String registerGCM() {
// below line I am getting error
gcm = GoogleCloudMessaging.getInstance(this);
regId = getRegistrationId(context);
if (TextUtils.isEmpty(regId)) {
registerInBackground();
Log.d("RegisterActivity",
"registerGCM - successfully registered with GCM server - regId: "
+ regId);
} else {
Toast.makeText(getApplicationContext(),
"RegId already available. RegId: " + regId,
Toast.LENGTH_LONG).show();
}
return regId;
}
#SuppressLint("NewApi")
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getSharedPreferences(
MainActivity.class.getSimpleName(), Context.MODE_PRIVATE);
String registrationId = prefs.getString(REG_ID, "");
if (registrationId.isEmpty()) {
Log.i(TAG, "Registration not found.");
return "";
}
int registeredVersion = prefs.getInt(APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
Log.i(TAG, "App version changed.");
return "";
}
return registrationId;
}
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
Log.d("RegisterActivity","I never expected this! Going down, going down!" + e);
throw new RuntimeException(e);
}
}
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regId = gcm.register(Config.GOOGLE_PROJECT_ID);
Log.d("RegisterActivity", "registerInBackground - regId: "
+ regId);
msg = "Device registered, registration ID=" + regId;
storeRegistrationId(context, regId);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
Log.d("RegisterActivity", "Error: " + msg);
}
Log.d("RegisterActivity", "AsyncTask completed: " + msg);
return msg;
}
#Override
protected void onPostExecute(String msg) {
Toast.makeText(getApplicationContext(),
"Registered with GCM Server." + msg,
Toast.LENGTH_LONG)
.show();
}
}.execute(null, null, null);
}
private void storeRegistrationId(Context context, String regId) {
final SharedPreferences prefs = getSharedPreferences(
MainActivity.class.getSimpleName(), Context.MODE_PRIVATE);
int appVersion = getAppVersion(context);
Log.i(TAG, "Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(REG_ID, regId);
editor.putInt(APP_VERSION, appVersion);
editor.commit();
}
}
Here, no need to import google_play_services_lib in your workspace, google_play_services_lib has a jar named google-play-services.jar which needs to be included in your GCM App.
google-play-services.jar contains all GCM related classes, thats why google_play_services_lib has been added as dependency on GCM Android Project. The simplest thing you can do is to add that jar on your GCM project instead of adding dependency of google_play_services_lib project.
To add jar in android project you have to do following things,
1. First create a libs folder under you project, its a libs folder and not lib.
2. Then copy google-play-services.jar inside libs folder.
3. Then right click on the google-play-services.jar and select Build Path > Add to Build Path.
You can see Android Private Libraries created under your project's root folder which will contain this jar.
Note: Path of jar file - sdk\extras\google\google_play_services\libproject\google-play-services_lib\libs
Related
I have this simple function that registers the user on the Google Messaging service
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regId = gcm.register(Config.GOOGLE_PROJECT_ID);
Log.d("RegisterActivity", "registerInBackground - regId: "
+ regId);
msg = "Device registered, registration ID=" + regId;
storeRegistrationId(context, regId);
appUtil.shareRegIdWithAppServer(context, regId);
Log.d("RegisterActivity", "should be rig: " + msg);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
Log.d("RegisterActivity", "Error: " + msg);
}
Log.d("RegisterActivity", "AsyncTask completed: " + msg);
return msg;
}
#Override
protected void onPostExecute(String msg) {
Toast.makeText(getApplicationContext(),
"Registered with GCM Server." + msg, Toast.LENGTH_LONG)
.show();
}
}.execute(null, null, null);
}
Edite
private void storeRegistrationId(Context context, String regId) {
final SharedPreferences prefs = getSharedPreferences(
MainActivity.class.getSimpleName(), Context.MODE_PRIVATE);
int appVersion = getAppVersion(context);
Log.i(TAG, "Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(REG_ID, regId);
editor.putInt(APP_VERSION, appVersion);
editor.commit();
}
End edite
When I execute it, it successfully registers on the GCM server and the user gets his registration ID successfully. BUT I get the following exception that stops and closes the application.
E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #1
Process: com.example.sparr_000.newgcm, PID: 25967
java.lang.RuntimeException: An error occured while executing doInBackground()
I am new to android. I have read the documentation, watched related videos and searched online but I found no solution.
What is wrong with my code and How can I get rid off this exception and continue running my app in peace?
There could be many places where the error might be as you have code running after the registration. Try to break your code into small pieces or use a debugger to know which step fails. Like comment out storeRegistrationId(context, regId);
appUtil.shareRegIdWithAppServer(context, regId);
and try running if it works then add the next or debug the rest of the functions to know which one fails.
Instead of sending the context, get the context of you application from the current class.
Hi am getting duplicate notification from gcm server , how to resolve it
public class RegisterActivity{
private GoogleCloudMessaging gcm;
Context context;
String regId;
private static final String REG_ID = "regId";
private static final String APP_VERSION = "appVersion";
static final String TAG = "Register Activity";
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private GCMRegistrationCallBack registeredActivity;
private Error error;
public void registerGCM(Context _context)
{
context = _context;
if(!checkPlayServices()){
Log.e(TAG, "This device is not supported.");
return;
}
registeredActivity = (GCMRegistrationCallBack) _context;
gcm = GoogleCloudMessaging.getInstance(context);
regId = getRegistrationId(context);
if(TextUtils.isEmpty(regId))
{
registerInBackground();
Log.d("RegisterActivity",
"registerGCM - successfully registered with GCM server - regId: "
+ regId);
}
else
{
registeredActivity.didFinishRegisteringWithGCM(regId);
}
}
private String getRegistrationId(Context context)
{
final SharedPreferences prefs = context.getSharedPreferences(
GCMRegistrationCallBack.class.getSimpleName(), Context.MODE_PRIVATE);
String registrationId = prefs.getString(REG_ID, "");
if (registrationId.isEmpty()) {
Log.i(TAG, "Registration not found.");
return "";
}
int registeredVersion = prefs.getInt(APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
Log.i(TAG, "App version changed.");
return "";
}
return registrationId;
}
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
Log.d("RegisterActivity",
"I never expected this! Going down, going down!" + e);
throw new RuntimeException(e);
}
}
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regId = gcm.register(Config.GOOGLE_PROJECT_ID);
storeRegistrationId(context, regId);
}
catch(UnknownHostException _exception)
{
error = new Error("UnknownHostException");
callErrorCallBackOnMainThread();
}
catch(SocketTimeoutException _exception)
{
error = new Error("SocketTimeoutException");
callErrorCallBackOnMainThread();
}
catch (IOException _exception) {
error = new Error(_exception.getMessage());
callErrorCallBackOnMainThread();
}
catch(Exception _exception)
{
error = new Error("unknown exception");
callErrorCallBackOnMainThread();
}
return regId;
}
#Override
protected void onPostExecute(String msg) {
if(!TextUtils.isEmpty(msg))
registeredActivity.didFinishRegisteringWithGCM(regId);
}
}.execute(null, null, null);
}
private void callErrorCallBackOnMainThread()
{
Activity regAvtivity = (Activity)registeredActivity;
regAvtivity.runOnUiThread(new Runnable()
{
public void run()
{
registeredActivity.didFailedToReceiveRegistrationId(error);
}
});
}
private void storeRegistrationId(Context context, String regId) {
final SharedPreferences prefs = context.getSharedPreferences(
GCMRegistrationCallBack.class.getSimpleName(), Context.MODE_PRIVATE);
int appVersion = getAppVersion(context);
Log.i(TAG, "Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(REG_ID, regId);
editor.putInt(APP_VERSION, appVersion);
editor.commit();
}
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, (Activity)context,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i(TAG, "This device is not supported.");
}
return false;
}
return true;
}
}
Above code for getting registration number please correct me anything wrong... but some time am getting duplicate notification.
thanks
You should use Canonical IDs for this. This might happen because you registered with several IDs for the same device. Using canonical IDs will set your ID to be the last registration you've made.
As per the GCM reference about this:
Canonical IDs
On the server side, as long as the application is behaving well, everything should work normally. However, if a bug in the application triggers multiple registrations for the same device, it can be hard to reconcile state and you might end up with duplicate messages.
GCM provides a facility called "canonical registration IDs" to easily recover from these situations. A canonical registration ID is defined to be the ID of the last registration requested by your application. This is the ID that the server should use when sending messages to the device.
If later on you try to send a message using a different registration ID, GCM will process the request as usual, but it will include the canonical registration ID in the registration_id field of the response. Make sure to replace the registration ID stored in your server with this canonical ID, as eventually the ID you're using will stop working.
More info here.
From my ASP.NET web service and using my GCM Browser API key I can successfully send a GCM Push Notification getting the following success response:
{"multicast_id":4623804699821154941,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1393876717064721%59cd098ff9fd7ecd"}
Two Problems:
1) The Google Developers Console shows 0 (zero) Requests and 0 Errors even after multiple 'Sends' and browser refreshes of the console page. Shouldn't the count change with every GCM Push Notification?
2) My Android device did not receive the push notification.
My code is modeled after:
remote server returned an error: (401) unathorized in C# GCM response
The passed in Android device ID was copied from a successful Android device registration.
My Server (web-service) code is below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.Text;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Collections.Specialized;
public class AndroidGCMPushNotification
{
public AndroidGCMPushNotification()
{
//
// TODO: Add constructor logic here
//
}
public string SendNotification(string deviceId, string message)
{
string BrowserAPIKey = "xxxxxxxxxxxxxxxxxxxxxxxxx"; // GCM Browser Key
string tickerText = "ticker test GCM";
string contentTitle = "content title GCM";
string postData = "{ \"registration_ids\": [ \"" + deviceId + "\" ], \"data\": {\"tickerText\":\"" + tickerText + "\", \"contentTitle\":\"" + contentTitle + "\", \"message\": \"" + message + "\"}}";
string sResponseFromServer = SendGCMNotification(BrowserAPIKey, postData);
return sResponseFromServer;
}
private string SendGCMNotification(string apiKey, string postData, string postDataContentType = "application/json")
{
String sResponseFromServer = "";
// from here:
// https://stackoverflow.com/questions/11431261/unauthorized-when-calling-google-gcm
//
// original:
// http://www.codeproject.com/Articles/339162/Android-push-notification-implementation-using-ASP
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
//
// MESSAGE CONTENT
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
//
// CREATE REQUEST
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
Request.Method = "POST";
Request.KeepAlive = false;
Request.ContentType = postDataContentType;
//Request.Headers.Add(string.Format("Authorization: key={0}", apiKey));
Request.Headers.Add(HttpRequestHeader.Authorization, String.Format("key={0}", apiKey));
Request.ContentLength = byteArray.Length;
//Stream dataStream;
try
{
Stream dataStream = Request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
}
catch (Exception e)
{
sResponseFromServer = e.Message;
}
//
// SEND MESSAGE
try
{
WebResponse Response = Request.GetResponse();
HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode;
if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden))
{
sResponseFromServer = "Unauthorized - need new token";
}
else if (!ResponseCode.Equals(HttpStatusCode.OK))
{
sResponseFromServer = "Response from web service isn't OK";
}
StreamReader Reader = new StreamReader(Response.GetResponseStream());
sResponseFromServer = Reader.ReadToEnd();
Reader.Close();
}
catch (Exception e)
{
sResponseFromServer = e.Message;
}
return sResponseFromServer;
}
public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return true;
}
}
On the Android client side I have the following notification-receive code:
package com.MichaelResslerFineArt.eclipmessenger;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import com.MichaelResslerFineArt.eclipmessenger.ProfileActivity;
import com.MichaelResslerFineArt.eclipmessenger.R;
import com.MichaelResslerFineArt.eclipmessenger.ProfileActivity.GcmBroadcastReceiver;
import com.MichaelResslerFineArt.eclipmessenger.ProfileActivity.GcmIntentService;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.app.Activity;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
public class ProfileActivity extends Activity {
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
String SENDER_ID = "594966827111"; // GCM Project Number
public static final String LOG_MSG_TAG = "eClipMessenger";
GoogleCloudMessaging gcm;
AtomicInteger msgId = new AtomicInteger();
SharedPreferences prefs;
Context context;
String regid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
context = getApplicationContext();
// Check device for Play Services APK.
GcmApi gcmApi = new GcmApi();
if (gcmApi.checkPlayServices(this)) {
// If this check succeeds, proceed with normal processing.
// Otherwise, prompt user to get valid Play Services APK.
Toast.makeText(this, "Success checking APK.", Toast.LENGTH_LONG).show();
Log.i(LOG_MSG_TAG, "Success checking APK.");
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (regid.isEmpty()) {
registerInBackground();
}
else {
Log.i(LOG_MSG_TAG, "GCM Reg ID: " + regid);
}
} else {
Log.i(LOG_MSG_TAG, "No valid Google Play Services APK found.");
}
}
// You need to do the Play Services APK check here too.
#Override
protected void onResume() {
super.onResume();
GcmApi gcmApi = new GcmApi();
gcmApi.checkPlayServices(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.profile, menu);
return true;
}
/**
* Gets the current registration ID for application on GCM service.
* <p>
* If result is empty, the app needs to register.
*
* #return registration ID, or empty string if there is no existing
* registration ID.
*/
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getGCMPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
Log.i(LOG_MSG_TAG, "Registration not found.");
return "";
}
// Check if app was updated; if so, it must clear the registration ID
// since the existing regID is not guaranteed to work with the new
// app version.
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
Log.i(LOG_MSG_TAG, "App version changed.");
return "";
}
return registrationId;
}
/**
* #return Application's {#code SharedPreferences}.
*/
private SharedPreferences getGCMPreferences(Context context) {
// This sample app persists the registration ID in shared preferences, but
// how you store the regID in your app is up to you.
return getSharedPreferences(ProfileActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
/**
* #return Application's version code from the {#code PackageManager}.
*/
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration ID and app versionCode in the application's
* shared preferences.
*/
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
// The request to your server should be authenticated if your app
// is using accounts.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device
// will send upstream messages to a server that echo back the
// message using the 'from' address in the message.
// Persist the regID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
//#Override
protected void onPostExecute(String msg) {
Log.i(LOG_MSG_TAG, msg);
//mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
/**
* Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
* or CCS to send messages to your app. Not needed for this demo since the
* device sends upstream messages to a server that echoes back the message
* using the 'from' address in the message.
*/
private void sendRegistrationIdToBackend() {
// Your implementation here.
}
/**
* Stores the registration ID and app versionCode in the application's
* {#code SharedPreferences}.
*
* #param context application's context.
* #param regId registration ID
*/
private void storeRegistrationId(Context context, String regId) {
Log.i(LOG_MSG_TAG, "entered storeRegistrationId()");
final SharedPreferences prefs = getGCMPreferences(context);
Log.i(LOG_MSG_TAG, "retrieved preferences");
int appVersion = getAppVersion(context);
Log.i(LOG_MSG_TAG, "Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROPERTY_REG_ID, regId);
editor.putInt(PROPERTY_APP_VERSION, appVersion);
editor.commit();
}
/*
public void sendGcm(final View view) {
if (view == findViewById(R.id.button2)) {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
Bundle data = new Bundle();
data.putString("my_message", "Hello World");
data.putString("my_action",
"com.google.android.gcm.demo.app.ECHO_NOW");
String id = Integer.toString(msgId.incrementAndGet());
gcm.send(SENDER_ID + "#gcm.googleapis.com", id, data);
msg = "Sent message";
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
Log.i(LOG_MSG_TAG, msg);
//mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
// } else if (view == findViewById(R.id.textView2)) {
// mDisplay.setText("");
}
}
*/
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(LOG_MSG_TAG, "onReceive");
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
public class GcmIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public GcmIntentService() {
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
/*
* Filter messages based on message type. Since it is likely that GCM
* will be extended in the future with new message types, just ignore
* any message types you're not interested in, or that you don't
* recognize.
*/
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());
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// This loop represents the service doing some work.
for (int i=0; i<5; i++) {
Log.i(LOG_MSG_TAG, "Working... " + (i+1)
+ "/5 # " + SystemClock.elapsedRealtime());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
Log.i(LOG_MSG_TAG, "Completed work # " + SystemClock.elapsedRealtime());
// Post notification of received message.
sendNotification("Received: " + extras.toString());
Log.i(LOG_MSG_TAG, "Received: " + extras.toString());
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
// Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendNotification(String msg) {
Log.i(LOG_MSG_TAG, "sendNotification");
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, ProfileActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("GCM Notification")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
}
And this separate class for checking the Play Services:
package com.MichaelResslerFineArt.eclipmessenger;
import android.app.Activity;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
public class GcmApi {
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
String SENDER_ID = "594966827111"; // GCM Project Number
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
public boolean checkPlayServices(ProfileActivity currActivity) {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(currActivity);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, currActivity,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i(ProfileActivity.LOG_MSG_TAG, "This device is not supported.");
Toast.makeText(currActivity, "This device is not supported.", Toast.LENGTH_LONG).show();
currActivity.finish();
}
return false;
}
return true;
}
}
And the Android client side manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.MichaelResslerFineArt.eclipmessenger"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<permission android:name="com.MichaelResslerFineArt.eclipmessenger.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.MichaelResslerFineArt.eclipmessenger.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.MichaelResslerFineArt.eclipmessenger.ProfileActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.MichaelResslerFineArt.eclipmessenger" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
</application>
</manifest>
GcmBroadcastReceiver and GcmIntentService shouldn't be inner classes of your activity class. They should be regular (top level) classes.
When you declare them as .GcmBroadcastReceiver and .GcmIntentService in your manifest, in means they should be located at com.MichaelResslerFineArt.eclipmessenger.GcmBroadcastReceiver and com.MichaelResslerFineArt.eclipmessenger.GcmIntentService, but since you implemented them as inner classes, they are actually located in com.MichaelResslerFineArt.eclipmessenger.ProfileActivity.GcmBroadcastReceiver and com.MichaelResslerFineArt.eclipmessenger.ProfileActivity.GcmIntentService, so they cannot be found when the message reaches your device.
Hi I am creating a chat application using xmpp. My problem is that while running the project a dialog box appears showing 'your project contain errors fix then and run', but there is no errors shown in project explorer, a warning is sign is shown(hope it doesn't effect rnuning a project). The console page is showing like this :
[2013-09-25 10:25:01 - Dex Loader] Unable to execute dex: Multiple dex files define Lcom/kenai/jbosh/AbstractAttr;
[2013-09-25 10:25:01 - XMPPChatDemo] Conversion to Dalvik format failed: Unable to execute dex: Multiple dex files define Lcom/kenai/jbosh/AbstractAttr;
And my program code is :
public class XMPPChatDemoActivity extends Activity {
public static final String HOST = "192.168.1.4";
public static final int PORT = 5222;
public static final String USERNAME = "semyma";
public static final String PASSWORD = "computer";
private XMPPConnection connection;
private ArrayList<String> messages = new ArrayList<String>();
private Handler mHandler = new Handler();
private EditText recipient;
private EditText textMessage;
private ListView listview;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
recipient = (EditText) this.findViewById(R.id.toET);
textMessage = (EditText) this.findViewById(R.id.chatET);
listview = (ListView) this.findViewById(R.id.listMessages);
setListAdapter();
// Set a listener to send a chat text message
Button send = (Button) this.findViewById(R.id.sendBtn);
send.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
String to = recipient.getText().toString();
String text = textMessage.getText().toString();
Log.i("XMPPChatDemoActivity", "Sending text " + text + " to " + to);
Message msg = new Message(to, Message.Type.chat);
msg.setBody(text);
if (connection != null) {
connection.sendPacket(msg);
messages.add(connection.getUser() + ":");
messages.add(text);
setListAdapter();
}
}
});
connect();
}
/**
* Called by Settings dialog when a connection is establised with the XMPP
* server
*
* #param connection
*/
public void setConnection(XMPPConnection connection) {
this.connection = connection;
if (connection != null) {
// Add a packet listener to get messages sent to us
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
connection.addPacketListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
Message message = (Message) packet;
if (message.getBody() != null) {
String fromName = StringUtils.parseBareAddress(message
.getFrom());
Log.i("XMPPChatDemoActivity", "Text Recieved " + message.getBody()
+ " from " + fromName );
messages.add(fromName + ":");
messages.add(message.getBody());
// Add the incoming message to the list view
mHandler.post(new Runnable() {
public void run() {
setListAdapter();
}
});
}
}
}, filter);
}
}
private void setListAdapter() {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
R.layout.listitem, messages);
listview.setAdapter(adapter);
}
#Override
protected void onDestroy() {
super.onDestroy();
try {
if (connection != null)
connection.disconnect();
} catch (Exception e) {
}
}
public void connect() {
final ProgressDialog dialog = ProgressDialog.show(this,
"Connecting...", "Please wait...", false);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
// Create a connection
ConnectionConfiguration connConfig = new ConnectionConfiguration(
HOST, PORT);
XMPPConnection connection = new XMPPConnection(connConfig);
try {
connection.connect();
Log.i("XMPPChatDemoActivity",
"Connected to " + connection.getHost());
} catch (XMPPException ex) {
Log.e("XMPPChatDemoActivity", "Failed to connect to "
+ connection.getHost());
Log.e("XMPPChatDemoActivity", ex.toString());
setConnection(null);
}
try {
// SASLAuthentication.supportSASLMechanism("PLAIN", 0);
connection.login(USERNAME, PASSWORD);
Log.i("XMPPChatDemoActivity",
"Logged in as " + connection.getUser());
// Set the status to available
Presence presence = new Presence(Presence.Type.available);
connection.sendPacket(presence);
setConnection(connection);
Roster roster = connection.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
for (RosterEntry entry : entries) {
Log.d("XMPPChatDemoActivity",
"--------------------------------------");
Log.d("XMPPChatDemoActivity", "RosterEntry " + entry);
Log.d("XMPPChatDemoActivity",
"User: " + entry.getUser());
Log.d("XMPPChatDemoActivity",
"Name: " + entry.getName());
Log.d("XMPPChatDemoActivity",
"Status: " + entry.getStatus());
Log.d("XMPPChatDemoActivity",
"Type: " + entry.getType());
Presence entryPresence = roster.getPresence(entry
.getUser());
Log.d("XMPPChatDemoActivity", "Presence Status: "
+ entryPresence.getStatus());
Log.d("XMPPChatDemoActivity", "Presence Type: "
+ entryPresence.getType());
Presence.Type type = entryPresence.getType();
if (type == Presence.Type.available)
Log.d("XMPPChatDemoActivity", "Presence AVIALABLE");
Log.d("XMPPChatDemoActivity", "Presence : "
+ entryPresence);
}
} catch (XMPPException ex) {
Log.e("XMPPChatDemoActivity", "Failed to log in as "
+ USERNAME);
Log.e("XMPPChatDemoActivity", ex.toString());
setConnection(null);
}
dialog.dismiss();
}
});
t.start();
dialog.show();
}
}
Most of the time this happens due to the multiple copies of android-support-v4 libraries in your project and and dependent project.
First try to delete the other android-support-v4 library and make it same for all.
if this works for you then its good other wise follow the below steps thats gonna work with you
1- List item
2-Open Project Build Path,
3-Select "Libraries" tab,
4-Remove all library except the Android Library
5-Adding all required JARs Files
And you are Done.
This error occurs you will better understand by this example - In case you download any project in this project environment means SDK updated in API LEVEL 15 and such type of project you import in your work-space and at this time point to be noted your SDK updated in API LEVEL
19 at this time fixed project setup and it will goes Build Path at this you just add external
libraries android-support-v4 then this problem has occurs due to the multiple copies of android-support-v4/google-play-services if you use Google map libraries in your project.
i hope so you will better understand.
Thankys
I am trying to do push notification in android using GCM. I read the Google docs for GCM and their demo application. I created the client side program mentioned here
http://android.amolgupta.in/. But i am not getting registration ID. Also I am not getting some points like:
do i need to server program too with this
on Google demo app they mention that i need to change api key at "samples/gcm-demo-server/WebContent/WEB-INF/classes/api.key" is it necessary to do it every time as i am creating new project
Can any one provide me proper project other than google provided so that i clear my concepts.
Any help will be appreciated.
Here I have written a few steps for How to Get RegID and Notification starting from scratch
Create/Register App on Google Cloud
Setup Cloud SDK with Development
Configure project for GCM
Get Device Registration ID
Send Push Notifications
Receive Push Notifications
You can find a complete tutorial here:
Getting Started with Android Push Notification : Latest Google Cloud
Messaging (GCM) - step by step complete tutorial
Code snippet to get Registration ID (Device Token for Push Notification).
Configure project for GCM
Update AndroidManifest file
To enable GCM in our project we need to add a few permissions to our manifest file. Go to AndroidManifest.xml and add this code:
Add Permissions
<uses-permission android:name="android.permission.INTERNET”/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name=“.permission.RECEIVE" />
<uses-permission android:name=“<your_package_name_here>.permission.C2D_MESSAGE" />
<permission android:name=“<your_package_name_here>.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
Add GCM Broadcast Receiver declaration in your application tag:
<application
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" ]]>
<intent-filter]]>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="" />
</intent-filter]]>
</receiver]]>
<application/>
Add GCM Service declaration
<application
<service android:name=".GcmIntentService" />
<application/>
Get Registration ID (Device Token for Push Notification)
Now Go to your Launch/Splash Activity
Add Constants and Class Variables
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
private final static String TAG = "LaunchActivity";
protected String SENDER_ID = "Your_sender_id";
private GoogleCloudMessaging gcm =null;
private String regid = null;
private Context context= null;
Update OnCreate and OnResume methods
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
context = getApplicationContext();
if (checkPlayServices()) {
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (regid.isEmpty()) {
registerInBackground();
} else {
Log.d(TAG, "No valid Google Play Services APK found.");
}
}
}
#Override
protected void onResume() {
super.onResume();
checkPlayServices();
}
// # Implement GCM Required methods(Add below methods in LaunchActivity)
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.d(TAG, "This device is not supported - Google Play Services.");
finish();
}
return false;
}
return true;
}
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getGCMPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
Log.d(TAG, "Registration ID not found.");
return "";
}
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
Log.d(TAG, "App version changed.");
return "";
}
return registrationId;
}
private SharedPreferences getGCMPreferences(Context context) {
return getSharedPreferences(LaunchActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
throw new RuntimeException("Could not get package name: " + e);
}
}
private void registerInBackground() {
new AsyncTask() {
#Override
protected Object doInBackground(Object...params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
Log.d(TAG, "########################################");
Log.d(TAG, "Current Device's Registration ID is: " + msg);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return null;
}
protected void onPostExecute(Object result) {
//to do here
};
}.execute(null, null, null);
}
Note : please store REGISTRATION_KEY, it is important for sending PN Message to GCM. Also keep in mind: this key will be unique for all devices and GCM will send Push Notifications by REGISTRATION_KEY only.
In response to your first question: Yes, you have to run a server app to send the messages, as well as a client app to receive them.
In response to your second question: Yes, every application needs its own API key. This key is for your server app, not the client.
Use this code to get Registration ID using GCM
String regId = "", msg = "";
public void getRegisterationID() {
new AsyncTask() {
#Override
protected Object doInBackground(Object...params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(Login.this);
}
regId = gcm.register(YOUR_SENDER_ID);
Log.d("in async task", regId);
// try
msg = "Device registered, registration ID=" + regId;
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
}.execute(null, null, null);
}
and don't forget to write permissions in manifest...
I hope it helps!