I am trying to set up GCM but my project doesn't recognize certain methods. I followed the advice of many other links which was to import GCM and google play services but I am still getting no such luck. Thanks for looking.
Edit: I've cleaned a million times and rebuilt.
I'm not sure where you got the code of the demo app from, but there are several things wrong with it.
First of all, the method you are missing is not implemented in the Demo. It has an empty body :
/**
* 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.
}
It's your responsibility to implement it, since its implementation depends on your server implementation.
Another error (you'd get an exception after you fix the compilation error) is calling gcm.register() from the main thread. You must call it in the background :
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mDisplay = (TextView) findViewById(R.id.display);
context = getApplicationContext();
// Check device for Play Services APK. If check succeeds, proceed with GCM registration.
if (checkPlayServices()) {
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (regid.isEmpty()) {
registerInBackground();
}
} else {
Log.i(TAG, "No valid Google Play Services APK found.");
}
}
/**
* Registers the application with GCM servers asynchronously.
* <p>
* Stores the registration ID and the 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.
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) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
All code samples are taken from the official GCM Demo app.
Related
I have this code. I enter the project key from the Google console as the snederId and get an error:
service not available.
which steps would you recommend for me to double check in setting up the registration key?
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.
sendRegistrationIdToBackend();
saveRegIdToDb();
// 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) {
// mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
Some basic checks:
Was your project whitelisted by Google?
Do you use the correct sender_id (project number)?
Is network connection up?
Are Google Play Services installed and up to date?
One of the above checks should not be OK.
check sender id, it is project number
and turn on "APIs & auth" -> "Google Cloud Messaging for Android"
I am using GCM. Its work perfect but after unregister i still receive notifications.
This is my registration:
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(context);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
GCMRegistrar.checkManifest(context);
registerReceiver(mHandleMessageReceiver, new IntentFilter(
DISPLAY_MESSAGE_ACTION));
// Get GCM registration id
final String regId = GCMRegistrar.getRegistrationId(context);
// Check if regid already presents
if (regId.equals("")) {
// Registration is not present, register now with GCM
GCMRegistrar.register(context, SENDER_ID);
} else {
// Device is already registered on GCM
if (GCMRegistrar.isRegisteredOnServer(context)) {
// Skips registration.
Toast.makeText(context, "Already registered with GCM", Toast.LENGTH_LONG).show();
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// Register on our server
// On server creates a new user
ServerUtilities.register(context, user, pass, regId);
return null;
}
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}`
And from different activity i am trying to unregister from GCM:
GCMRegistrar.unregister(getApplicationContext());
GCMRegistrar.onDestroy(getApplicationContext());
And after that i still receive notifications :(
First, GCMRegistrar is deprecated.
Second, unregister() indicates that this device should never again receive messages. Frequently registering and unregistering is not expected app behavior. If you want to stop receiving messages, tell your app server to stop sending them.
My aplication is a multiplayer game in android, with a server running on google app engine and using GCM to conect the server with the player devices. i have registered the device in GCM and then i sent the registerId to the server to connect with the device. When i run the game sometimes it works fine but sometimes the device doesn¡t receive anything from GCM, the server still receive from the device. I have no idea what is happening :s
Here is where i register my device in the onCreate of the main class :
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
if (GCMRegistrar.isRegistered(this)) {
Log.d("info", GCMRegistrar.getRegistrationId(this));
}
regId = GCMRegistrar.getRegistrationId(this);
deviceId = getDeviceId();
if (regId.equals("")) {
GCMRegistrar.register(this, SENDER_ID);
Log.d("info", GCMRegistrar.getRegistrationId(this));
}
Then the first time i run the application on a phone i use this code to send the registationId to the server:
sendMessage("code=" + REGISTRATION_CODE +
"&deviceId=" + deviceId +
"®Id=" + regId +
"&phoneNumber=" + phoneNumber);
And here is the code in the server to send messages back to the device:
public void sendMessage(String regId, String text) {
Sender sender = new Sender(APIKey);
Message message = new Message.Builder().collapseKey("1").timeToLive(3).delayWhileIdle(true).addData("message", text).build();
try {
sender.send(message,regId,1);
} catch (IOException e) {
e.printStackTrace();//Manejar la excepcion
}
}
I can't understand why stop working, i'm in the middle of a game and stops working and then works again ...
I just solved it, the problem was the collapseKey here
Message message = new Message.Builder().collapseKey("1").timeToLive(3).delayWhileIdle(true).addData("message", text).build();
If you use the same collapseKey always sometimes you don't receive messages randomly so i try this and works finally works!!
Message message = new Message.Builder().collapseKey(""+((int) (Math.random () * (10000)))).timeToLive(3).delayWhileIdle(true).addData("message", text).build();
I am banging my head on the wall. It works, but it doesn't work.
Let me clarify, testing is on a LG Optimus G, A Galaxy S4, and a Lenovo Tablet all running 4.1+
I am launching a server on each device, each device is broadcasting itself on a port, and when the user hits send, all devices that have had their service resolved, and their service has not been lost, a thread will loop launching other threads to connect to the servers broadcasting themselves, and send the data. The servers accept the incoming connection, hand it off to a thread, and then re-open themselves.
So recap, every device has is broadcasting a server, every device is supposed to know and keep track of other servers, when data is sent all known servers get hit.
My issue is that in 2/3 devices connections can consistently be established with the device's self.
Either phone, but only 1 of them at a time, seems to know about the other phone and is able to connect to the other phone. i.e. Galaxy S4 can say hi to Optimus G, but Optimus G cannot say hi except only to itself, or vice-verse.
So the discovering portion seems unreliable, and I do not know if it is me, Android, or the devices. I need outside eyes. I have tried to lay this out in a understandable and thought out manner, and I appreciate any help from any one who has knowledge on this issue as I am just making humble beginnings into the world of networks, and am more then willing to learn from someone.
I need a more reliable way of keeping track of services, or discovering them, as my implementation at least seems flawed.
I thank any help in advanced. (I do not believe this is a area that is trodden as heavily as most other android areas.)
Here is where the initialization is done.
/**initilize everything*/
private void buildNetwork()
{
Log.d(TAG, "buildNetwork");
networkHelper = new NetworkServiceDiscoveryHelper(this);
networkHelper.initializeNsd(this);
networkHelper.discoverServices();
connectionReceiver = new ConnectionReceiver(this, this);
// this next line launches the server thread which will obtain a socket
// to be used in the finishBuildingNetwork()
new Thread(connectionReceiver).start();
}
/** after the serversocket has been given a port we need to broadcast it*/
private void finishBuildingNetwork(int port)
{
Log.d(TAG, "finishBuildingNetwork");
networkHelper.registerService(port);
}
This is my somewhat changed implementation of a common NSDManager helper class.
public class NetworkServiceDiscoveryHelper
{
public static final String TAG = "NetworkServiceDiscoveryHelper";
public static final String KEY_DEVICE = "device";
Context mContext;
NsdManager mNsdManager;
NsdManager.ResolveListener mResolveListener;
NsdManager.DiscoveryListener mDiscoveryListener;
NsdManager.RegistrationListener mRegistrationListener;
public static final String SERVICE_TYPE = "_http._tcp.";
public String mServiceName = "BlurbChat";
NsdServiceInfo mService;
private DiscoveredDevicesManager deviceManager;
private NetworkDiscoveryHelperListener helperListener;
/**
*
* #param context
* - the activity context the service is to be attached to
*/
public NetworkServiceDiscoveryHelper(Context context)
{
mContext = context;
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
deviceManager = new DiscoveredDevicesManager();
}
/**
* initialize the NetworkServiceDiscovery
*/
public void initializeNsd(NetworkDiscoveryHelperListener helperListener)
{
this.helperListener = helperListener;
initializeResolveListener();
initializeDiscoveryListener();
initializeRegistrationListener();
// mNsdManager.init(mContext.getMainLooper(), this);
}
private void initializeDiscoveryListener()
{
mDiscoveryListener = new NsdManager.DiscoveryListener()
{
#Override
public void onDiscoveryStarted(String regType)
{
Log.d(TAG, "Service discovery started");
helperListener.SERVICE_STARTED(regType);
}
#Override
public void onServiceFound(NsdServiceInfo service)
{
// A service was found! Do something with it.
Log.d(TAG, "Service discovery success" + service);
if (!service.getServiceType().equals(SERVICE_TYPE))
{
// Service type is the string containing the protocol and
// transport layer for this service.
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
}
else if (service.getServiceName().contains(mServiceName))
{
// we have found our service! we use .contains because if
// there are multiple device with the same service being
// broadcast they will appear with name + (index)
// Resolve a discovered service. An application can resolve
// a service right before establishing a connection to fetch
// the IP and port details on which to setup the connection.
Log.d(TAG, "Found My Service Type: " + service.getServiceType() + service.getServiceName());
helperListener.SERVICE_FOUND(service);
mNsdManager.resolveService(service, mResolveListener);
}
/***************************************************************
* Checking the service name isn't always necessary, and is only relevant if you want to connect to a specific application.
* For instance, the application might only want to connect to instances of itself running on other devices. However, if the
* application wants to connect to a network printer, it's enough to see that the service type is "_ipp._tcp".
******************************************************/
}
/**
* when we lose our service
*/
#Override
public void onServiceLost(NsdServiceInfo service)
{
// When the network service is no longer available.
Log.e(TAG, "service lost" + service);
// remove the service
if (deviceManager.removeDevice(service) != null)
{
helperListener.SERVIVCE_LOST(service);
}
}
/**
* when our service is stopped
*/
#Override
public void onDiscoveryStopped(String serviceType)
{
Log.i(TAG, "Discovery stopped: " + serviceType);
helperListener.DISCOVERY_STOPPED(serviceType);
}
#Override
public void onStartDiscoveryFailed(String serviceType, int errorCode)
{
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
helperListener.DISCOVERY_START_FAILED(serviceType, errorCode);
mNsdManager.stopServiceDiscovery(this);
}
#Override
public void onStopDiscoveryFailed(String serviceType, int errorCode)
{
helperListener.DISCOVERY_STOP_FAILED(serviceType, errorCode);
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}
private void initializeResolveListener()
{
mResolveListener = new NsdManager.ResolveListener()
{
#Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode)
{
// Called when the resolve fails. Use the error code to debug.
Log.e(TAG, "Resolve failed" + errorCode);
helperListener.RESOLVE_FAILED(serviceInfo, errorCode);
}
#Override
public void onServiceResolved(NsdServiceInfo serviceInfo)
{
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getServiceName().equals(mServiceName))
{
Log.d(TAG, "Same IP.");
return;
}
mService = serviceInfo;
DiscoveredDevice device = new DiscoveredDevice(mService.getPort(), mService.getHost(), mService.getServiceName(), mService.getServiceType());
deviceManager.addDevice(device);
helperListener.RESOLVE_SUCCESS(serviceInfo);
}
};
}
private void initializeRegistrationListener()
{
mRegistrationListener = new NsdManager.RegistrationListener()
{
#Override
public void onServiceRegistered(NsdServiceInfo serviceInfo)
{
mServiceName = serviceInfo.getServiceName();
helperListener.SERVICE_REGISTERED(serviceInfo);
}
#Override
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode)
{
helperListener.SERVICE_REGISTRATION_FAILED(serviceInfo, errorCode);
}
#Override
public void onServiceUnregistered(NsdServiceInfo serviceInfo)
{
helperListener.SERVICE_UNREGISTERED(serviceInfo);
}
#Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode)
{
helperListener.SERVICE_UNREGISTRATION_FAILED(serviceInfo, errorCode);
}
};
}
/**
* To be called after initialize()
*
* #param port
* - the port you would like to register/broadcast the service through.
*/
public void registerService(int port)
{
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setPort(port);
serviceInfo.setServiceName(mServiceName);
serviceInfo.setServiceType(SERVICE_TYPE);
mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
}
/**
* Initiate service discovery to browse for instances of a service type. Service discovery consumes network bandwidth and will continue
* until the application calls stopServiceDiscovery(NsdManager.DiscoveryListener).
*/
public void discoverServices()
{
mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
/**
* Stop service discovery initiated with discoverServices(String, int, NsdManager.DiscoveryListener). An active service discovery is
* notified to the application with onDiscoveryStarted(String) and it stays active until the application invokes a stop service
* discovery. A successful stop is notified to with a call to onDiscoveryStopped(String).
*/
public void stopDiscovery()
{
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
/**
*
* #return - A class representing service information for network service discovery
*/
public NsdServiceInfo getChosenServiceInfo()
{
return mService;
}
/**
* Unregister a service registered through registerService(NsdServiceInfo, int, NsdManager.RegistrationListener). A successful
* unregister is notified to the application with a call to onServiceUnregistered(NsdServiceInfo).
*/
public void tearDown()
{
if (mNsdManager != null)
{
try
{
mNsdManager.unregisterService(mRegistrationListener);
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
/**
*
* #return - the DiscoveredDevicesManager that contains all valid devices which have the appropriate service susally will call this
* after a msg of RESOLVE_SUCCESS
*/
public DiscoveredDevicesManager getDeviceManager()
{
return deviceManager;
}
}
and finally this is the basis of the server
#Override
public void run()
{
try
{
receiverSocket = new ServerSocket(0);
onPortObtained(receiverSocket.getLocalPort());
Log.d(TAG, "run");
while (broadcastConnection)
{
try
{
Socket newConnectionSocket = receiverSocket.accept();
onNewConnection(newConnectionSocket.getRemoteSocketAddress(), newConnectionSocket.getLocalSocketAddress());
// to clarify this line launches a function that starts threads to handle the socket.
recieveConnection(newConnectionSocket);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
Edit: one more thing, sometimes while running the devices will randomly restart. No common thing causing, other then they are running the app.
With the service discovery being just to difficult to handle, I will build my own discovery by doing a initial ping like so
List<DiscoveredDevice> devices = new ArrayList<DiscoveredDevice>();
for (int i = 0; i < 256; i++)
{
// this hardcoded ip will be variable from the wifi's ip
String ip = "xx.xx.x." + i;
// this socket may be forever hard coded unless i find a better way. :(
devices.add(new DiscoveredDevice(32999, ip, "", ""));
}
hitting all devices, registering every device that accepts, and every device that accepts registering it.
On leave it will dispatch a command to be removed from every devices queue, and upon trying to send a device a connection that does not get accepted it will be removed.
Hackish, but the Android way wasn't working for me :(, and this way works beautifully.
I'm currently using Topic based communication using JADE. I'm able to register a JADE agent using jade.core.messaging.TopicManagementFEService thereby connecting to the main-container in the same platform.
The details are below:
Main-Container: a simple LAMP/WAMP Server that hosts the Main-Container.
Client: An Android Emulator(testing purpose) to connect to the main-container.
Currently,
Server starts the main-container
Android emulator connects to the Main-container successfully (Agent created along with Topic Mgmt Service enabled)
Server is sending messages based on a specific topic.
But my Android Client is not able to receive this message although the topic registered is the same on both ends!
You can see the code below:
Server Side:
TopicManagementHelper topicHelper = (TopicManagementHelper) getHelper(TopicManagementHelper.SERVICE_NAME);
final AID sensorTopic = topicHelper.createTopic("JADE");
topicHelper.register(sensorTopic);
addBehaviour(new TickerBehaviour(this, TIMER_VALUE_IN_MILLISECONDS) {
private static final long serialVersionUID = -2567778187494378326L;
public void onTick() {
ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
msg.addReceiver(eventTopic);
msg.setContent(eventValue);
myAgent.send(msg);
}
});
Android Side:
// Registering on Android Side as well
TopicManagementHelper topicHelper = (TopicManagementHelper) getHelper(TopicManagementHelper.SERVICE_NAME);
topic = topicHelper.createTopic("JADE"); // See, same topic!
topicHelper.register(topic);
behaviour = new myBehaviour(this, TIMER_VALUE_IN_MILLISECONDS, topic);
addBehaviour(behaviour);
private class myBehaviour extends TickerBehaviour {
private static final long serialVersionUID = 4782913834042415090L;
AID topic;
Agent agent;
MessageTemplate tpl;
public myBehaviour(Agent a, long period, AID topic) {
super(a, period);
this.agent = a;
this.topic = topic;
}
public void onTick() {
tpl = MessageTemplate.MatchTopic(topic);
ACLMessage msg = receive(tpl);
if (msg != null) {
logger.log(Level.INFO, "Agent "+ agent.getLocalName() +
": Message about topic "+ topic.getLocalName() +" received. \n" +
"Content is " + msg.getContent());
data = msg.getContent();
} else {
logger.log(Level.INFO, "In here..."); // Always executes only this code!
block();
}
}
}
Where am I going wrong here? It always executes the else part in the Android side which is obvious to say that message received is NULL!
Never mind. The logic was wrong. The Android-Agent was not identifying itself to the Central-Agent.
I set the Ontology so that the Central Agent is able to identify such message and sends the message accordingly. Now, it is receiving messages!
Self-help works sometimes! ;-)
Receiving topic messages doesn't work correctly with Android up to version 4.3.0 in JADE. Android can send out topic messages but can't receive them. I found this out through my own issues. I've posted more info about it in my own question on stack overflow.
Take a look. JADE Leap Android App unable to receive topic messages