I'm following this tutorial to receive push notifications on my android device.
I can send push notifications from the Firebase console - and I can also see the Firebase event in logcat but my onMessageReceived is never fired. My app is running in the foreground.
Here is the output in logcat after I send a notification:
12-31 12:23:54.741 9453-11132/com.example.app D/FA: Logging event (FE): notification_receive(_nr), Bundle[{firebase_event_origin(_o)=fcm, firebase_screen_class(_sc)=MainActivity, firebase_screen_id(_si)=407943440756026938, message_device_time(_ndt)=0, message_name(_nmn)=Label Arse, message_time(_nmt)=1514723034, message_id(_nmid)=3115372290763926350}]
12-31 12:23:54.784 9453-11132/com.example.app V/FA: Connecting to remote service
12-31 12:23:54.797 9453-11132/com.example.app D/FA: Logging event (FE): notification_foreground(_nf), Bundle[{firebase_event_origin(_o)=fcm, firebase_screen_class(_sc)=MainActivity, firebase_screen_id(_si)=407943440756026938, message_device_time(_ndt)=0, message_name(_nmn)=Label Arse, message_time(_nmt)=1514723034, message_id(_nmid)=3115372290763926350}]
12-31 12:23:54.828 9453-11132/com.example.app V/FA: Connection attempt already in progress
12-31 12:23:54.829 9453-11132/com.example.app D/FA: Connected to remote service
12-31 12:23:54.829 9453-11132/com.example.app V/FA: Processing queued up service tasks: 2
12-31 12:23:59.875 9453-11132/com.example.app V/FA: Inactivity, disconnecting from the service
MyFirebaseMessageingService.java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
}
}
FirebaseIDService.java
public class FirebaseIDService extends FirebaseInstanceIdService {
private static final String TAG = "FirebaseIDService";
#Override
public void onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
// Add custom implementation, as needed.
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:hardwareAccelerated="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".services.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true" />
<service
android:name=".services.FirebaseIDService"
android:enabled="true"
android:exported="true"></service>
</application>
</manifest>
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.example.app"
minSdkVersion 17
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/java/services']
}
}
}
repositories {
maven { url "https://jitpack.io" }
}
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.google.firebase:firebase-messaging:11.8.0'
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.volley:volley:1.1.0'
compile 'com.google.code.gson:gson:2.8.2'
compile 'com.github.PhilJay:MPAndroidChart:v2.1.6'
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.4.0'
compile 'com.google.firebase:firebase-appindexing:11.8.0'
compile files('libs/glide-full-4.3.1.jar')
}
apply plugin: 'com.google.gms.google-services'
as per google firebase messaging guide
try replacing your service tag in the manifest file with :
<service
android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
in the onMessageReceived() refer here you can get the notification / data payload :
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " +
remoteMessage.getNotification().getBody());
}
}
}
Related
I'm making an app which can write to firebase database on button click.
The app is working on emulator but it's not working on my physical device.
Here's the main activity code:
public class MainActivity extends AppCompatActivity {
private Firebase fled1;
Button on;
Button off;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
on= findViewById(R.id.on);
off= findViewById(R.id.off);
on.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
fled1 = new Firebase("https://iotapp-6y3n8.firebaseio.com/");
Firebase fled1Child = fled1.child("S1");
fled1Child.setValue("1");
}
});
off.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
fled1 = new Firebase("https://iotapp-6y3n8.firebaseio.com/");
Firebase fled1Child = fled1.child("S1");
fled1Child.setValue("0");
}
});
}
Here's my manifest file I have added all the permissions required:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.lalitahuja.iotbutton">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name="com.example.lalitahuja.iotbutton.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Here's the build Gradle file:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.lalitahuja.iotbutton"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//noinspection GradleCompatible
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.google.firebase:firebase-core:16.0.8'
implementation 'com.google.firebase:firebase-database:16.1.0'
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.7'
implementation 'com.google.firebase:firebase-auth:16.2.0'
implementation 'com.firebase:firebase-client-android:2.5.2'
}
apply plugin: 'com.google.gms.google-services'
The error I'm getting:
E/FirebaseInstanceId: Token retrieval failed: SERVICE_NOT_AVAILABLE
W/MessengerIpcClient: Timing out request: 1
E/FirebaseInstanceId: Token retrieval failed: SERVICE_NOT_AVAILABLE
W/MessengerIpcClient: Timing out request: 2
E/FirebaseInstanceId: Token retrieval failed: SERVICE_NOT_AVAILABLE
W/MessengerIpcClient: Timing out request: 3
W/MessengerIpcClient: Received response for unknown request: 3
E/FirebaseInstanceId: Failed to resolve target intent service, skipping classname enforcement
E/FirebaseInstanceId: Error while delivering the message: ServiceIntent not found.
W/MessengerIpcClient: Received response for unknown request: 1
W/MessengerIpcClient: Received response for unknown request: 2
I've looked over all the answers I could find, the particular function of code isn't working even in foreground. I tried changing the manifest, changing the code, all i get in the logger are these 2 of these things:
D/FA: Logging event (FE): notification_receive(_nr), ...
This is my manifest file:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#drawable/avatar"
android:label="#string/app_name"
android:roundIcon="#drawable/avatar"
android:supportsRtl="true"
android:theme="#style/Theme.AppCompat.Light.NoActionBar">
<activity android:name=".StartActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"/>
<service android:name=".GettingDeviceTokenService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".NotificationService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
And here is the notification service:
public class NotificationService extends FirebaseMessagingService {
public static int NOTIFICATION_ID = 1;
private static final String CHANNEL_ID = "1";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d("+++", remoteMessage.toString());
if (remoteMessage.getData().size() > 0) {
Log.d("dataa", "Data Payload: " + remoteMessage.getData().toString());
}
}
This is the app gradle file
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.example.xghos.Wrenchy"
minSdkVersion 21
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'net.hockeyapp.android:HockeySDK:5.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'de.hdodenhof:circleimageview:2.2.0'
implementation 'com.google.firebase:firebase-core:16.0.1'
implementation 'com.google.firebase:firebase-messaging:17.3.0'
implementation 'com.ethanhua:skeleton:1.1.1'
implementation 'io.supercharge:shimmerlayout:2.1.0'
implementation "com.daimajia.swipelayout:library:1.2.0#aar"
}
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion '26.1.0'
}
}
}
}
apply plugin: 'com.google.gms.google-services'
and the GettingDeviceTokenService:
package com.example.xghos.Wrenchy;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class GettingDeviceTokenService extends FirebaseMessagingService {
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.d("DeviceToken ==> ", s);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
}
}
EDIT: the problem was solved by changing the intent filter of the GettingDeviceTokenService from
<action android:name="com.google.firebase.MESSAGING_EVENT" />
to
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
You should consider difference between data message and display message.
Display message has payload with key notification and are automatically displayed when app is in background and also call onMessageReceived() if app is already in foreground.
Data message has payload key data . They always invoke onMessageReceived()
You have registered NotificationService service in your manifest. Since latest update for firebase notifications, the same service will handle new token and received messages. In your case you should register in manifest only GettingDeviceTokenService because you override both methods and remove NotificationService.
Try this way. It worked for me Perfectly.
1. Create a Service
public class YourService extends FirebaseMessagingService {
public static int NOTIFICATION_ID = 1;
#Override
public void onNewToken(String s) {
super.onNewToken(s);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder mNotifyBuilder = new NotificationCompat.Builder(this, "2")
.setSmallIcon(R.drawable.your_icon)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setContentText(remoteMessage.getNotification().getBody())
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (NOTIFICATION_ID > 1073741824) {
NOTIFICATION_ID = 0;
}
Objects.requireNonNull(notificationManager).notify(NOTIFICATION_ID++, mNotifyBuilder.build());
}
}
Now add this to Manifest
<service
android:name=".YourService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Im trying to add FCM notifications to my app, but for some reason
FirebaseInstanceId.getInstance().getToken();
is returning null.
Since im not getting any stacktrace my best guess is that FirebaseInstanceIdService is not working
Google Play Services version: 9.6.1
Firebase-messaging version : 9.6.1
added json config file from FirebaseConsole (Tried single file with 2 clients inside it, one for debug and one for release build) and 2 files each for respective build
Iw applied google services plugin at the bottom of my modules gradle script
Included google services in projects root gradle script
Created 2 services from the officail docs:
public class MyFirebaseInsanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
PreferencesHelper.putSharedPreferencesString(Constants.User.PUSH_NOTIFICATIONS, refreshedToken);
Log.e("TOKEN", "Token: " + FirebaseInstanceId.getInstance().getToken());
}
}
And the manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.fc.test">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="fctest"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="${appName}${appNameSuffix}"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:node="replace">
<service
android:name="com.fc.test.MyFirebaseInsanceIDService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name="com.fc.test.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<activity
android:name="com.fc.test.view.splash.Splash"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.CenterAnimation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
root Gradle:
buildscript {
repositories {
jcenter()
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
//noinspection GradleDynamicVersion
classpath 'io.fabric.tools:gradle:1.+'
classpath 'com.google.gms:google-services:3.0.0'
}
}
allprojects {
repositories {
jcenter()
maven { url "http://dl.bintray.com/drummer-aidan/maven" }
maven { url "https://maven.fabric.io/public" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "https://jitpack.io" }
}
}
ext {
buildToolsVersion = '24.0.1'
compileSdkVersion = 24
minSdkVersion = 15
targetSdkVersion = 24
supportLibraryVersion = '24.2.1'
}
and the main part of the modules Gradle
dependencies {
final PLAY_SERVICES_VERSION = '9.6.1'
final SUPPORT_LIBRARY_VERSION = '24.2.1'
final RETROFIT_VERSION = '2.1.0'
final DAGGER_VERSION = '2.5'
final DEXMAKER_VERSION = '1.4'
final HAMCREST_VERSION = '1.3'
final ESPRESSO_VERSION = '2.2.1'
final RUNNER_VERSION = '0.4'
final BUTTERKNIFE_VERSION = '8.1.0'
def daggerCompiler = "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
def jUnit = "junit:junit:4.12"
def mockito = "org.mockito:mockito-core:1.10.19"
// App Dependencies
compile "com.google.android.gms:play-services-gcm:$PLAY_SERVICES_VERSION"
compile "com.google.firebase:firebase-messaging:$PLAY_SERVICES_VERSION"
compile "com.android.support:appcompat-v7:$SUPPORT_LIBRARY_VERSION"
compile "com.android.support:recyclerview-v7:$SUPPORT_LIBRARY_VERSION"
compile "com.android.support:cardview-v7:$SUPPORT_LIBRARY_VERSION"
compile "com.android.support:design:$SUPPORT_LIBRARY_VERSION"
compile "com.android.support:support-annotations:$SUPPORT_LIBRARY_VERSION"
compile "com.android.support:support-v4:$SUPPORT_LIBRARY_VERSION"
compile "com.squareup.retrofit2:retrofit:$RETROFIT_VERSION"
compile "com.squareup.retrofit2:converter-gson:$RETROFIT_VERSION"
compile "com.squareup.retrofit2:adapter-rxjava:$RETROFIT_VERSION"
compile "com.jakewharton:butterknife:$BUTTERKNIFE_VERSION"
compile('com.crashlytics.sdk.android:crashlytics:2.6.5#aar') {
transitive = true;
}
}
apply plugin: 'com.google.gms.google-services
Note that im using tools:node="replace" in my root application tag.
Is it possible that FirebaseInstanceIdService is not added to the manifest since it has the same intent filter as mine FirebaseInstanceService and thus not being called?
So my question here would be is there something wrong it the official docs or in my implementation that should cause the Instance token to be null?
After digging up thru old implementations of FCM and generated manifests, I can now say that manifest merger is the problem.
Solution for this problem is adding these classes to the apps manifest manualy
<activity
android:name="com.google.android.gms.common.api.GoogleApiActivity"
android:exported="false"
android:theme="#android:style/Theme.Translucent.NoTitleBar" />
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<service
android:name="com.google.firebase.messaging.FirebaseMessagingService"
android:exported="true" >
<intent-filter android:priority="-500" >
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.fc.debug" />
</intent-filter>
</receiver>
<receiver
android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
android:exported="false" />
<!--
-->
<service
android:name="com.google.firebase.iid.FirebaseInstanceIdService"
android:exported="true" >
<intent-filter android:priority="-500" >
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<provider
android:name="com.google.firebase.provider.FirebaseInitProvider"
android:authorities="com.fc.debug.firebaseinitprovider"
android:exported="false"
android:initOrder="100" />
<receiver
android:name="com.google.android.gms.measurement.AppMeasurementReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="com.google.android.gms.measurement.UPLOAD" />
</intent-filter>
</receiver>
<service
android:name="com.google.android.gms.measurement.AppMeasurementService"
android:enabled="true"
android:exported="false" />
While I was doing the migration I had a problem, it was that I didn't receive any Notification. To solve this and If you have your GCM working, don't forget to include your sender ID when you get the Firebase Token. To consult this ID you have to navigate to your Firebase project and click Project Name. Click the Setting icon and select "Project Setting" menu Select "Could Messaging" tab and use sender ID on the page.
And when says to code this:
token = FirebaseInstanceId.getInstance().getToken();
You have to use this:
token = FirebaseInstanceId.getInstance().getToken("YOUR_SENDER_ID", "FCM");
It works for me, I hope this helps you ;)
This worked for me:
String token = FirebaseInstanceId.getInstance().getInstanceId().getResult().getToken();
First genarate "google-services.json" and Add this file in your android studio Like this projectFolder/APP/google-services.json
Add classpath to top level build.gradle
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.google.gms:google-services:3.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
Add following plugin and dependencies in app’s build.gradle
apply plugin: 'com.google.gms.google-services'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.google.firebase:firebase-core:9.4.0'
compile 'com.google.firebase:firebase-messaging:9.4.0'
}
Add following Firebase services in your java files
FirebaseIDService.java
package com.galleonsoft.firebase.push;
import android.util.Log;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;
public class FirebaseIDService extends FirebaseInstanceIdService {
private static final String TAG = "FirebaseIDService";
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
// Add custom implementation, as needed.
}
}
MyFirebaseMessagingService.java
package com.galleonsoft.firebase.push;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class MyFirebaseMEssagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO: Handle FCM messages here.
// If the application is in the foreground handle both data and notification messages here.
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated.
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
}
}
Add service in your AndroidMainifest.xml file
<service android:name=".MyFirebaseMEssagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service android:name=".FirebaseIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
I am new to this, but trying to get a v simple example working of sending a message from my Wearable to my Phone. I have read other similar questions, but I can't find the solution amongst the answers I have read.
My problem is the onMessageReceived method in my Listener (running on my Mobile) is never called.
I am using real devices, Sony SmartWatch 3 and Samsung S5
What I have working is
My wearable sends the message (using Wearable.MessageApi.sendMessage) and outputs to the log that the message is successfully sent to the correct node.
What I have tried based on other similar questions I have read :-
Package in AndroidManifest is same between Mobile and Wearable
applicationId is same in build.gradle file between Mobile and Wearable
Uninstalling the apps from both Mobile and Wearable and running apps from Android Studio (not in debug mode)
Any guidance very gratefully received, please see my code below.
Thanks
Mobile Code
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.davidson.anothermessagetest" >
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".ListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
</application>
</manifest>
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.davidson.anothermessagetest"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
wearApp project(':wear')
compile 'com.android.support:appcompat-v7:23.2.0'
compile 'com.google.android.gms:play-services:8.4.0'
}
ListenerService
package com.davidson.anothermessagetest;
import android.util.Log;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.WearableListenerService;
/**
* Created by ddavidson on 09/03/2016.
*/
public class ListenerService extends WearableListenerService {
#Override
public void onMessageReceived(MessageEvent messageEvent) {
Log.v("myTag", "onMessageReceived:");
if (messageEvent.getPath().equals("/message_path")) {
final String message = new String(messageEvent.getData());
Log.v("myTag", "Message path received on watch is: " + messageEvent.getPath());
Log.v("myTag", "Message received on watch is: " + message);
}
else {
super.onMessageReceived(messageEvent);
}
}
#Override
public void onPeerConnected(Node peer) {
Log.v("myTag", "onPeerConnected:");
}
}
Wearable Code
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.davidson.anothermessagetest" >
<uses-feature android:name="android.hardware.type.watch" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#android:style/Theme.DeviceDefault" >
<activity
android:name=".MainActivity"
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" />
</application>
</manifest>
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.davidson.anothermessagetest"
minSdkVersion 20
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.google.android.support:wearable:1.3.0'
compile 'com.google.android.gms:play-services-wearable:8.4.0'
}
MainActivity
package com.davidson.anothermessagetest;
import android.app.Activity;
import android.os.Bundle;
import android.support.wearable.view.WatchViewStub;
import android.util.Log;
import android.widget.TextView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
public class MainActivity extends Activity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
GoogleApiClient googleClient;
private TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.v("myTag", "Wearable: onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
}
});
// Build a new GoogleApiClient for the Wearable API
googleClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
// Connect to the data layer when the Activity starts
#Override
protected void onStart() {
super.onStart();
googleClient.connect();
}
// Send a message when the data layer connection is successful.
#Override
public void onConnected(Bundle connectionHint) {
String message = "Hello wearable\n Via the data layer";
//Requires a new thread to avoid blocking the UI
new SendToDataLayerThread("/message_path", message).start();
}
// Disconnect from the data layer when the Activity stops
#Override
protected void onStop() {
if (null != googleClient && googleClient.isConnected()) {
googleClient.disconnect();
}
super.onStop();
}
// Placeholders for required connection callbacks
#Override
public void onConnectionSuspended(int cause) { }
#Override
public void onConnectionFailed(ConnectionResult connectionResult) { }
public class SendToDataLayerThread extends Thread {
String path;
String message;
// Constructor to send a message to the data layer
SendToDataLayerThread(String p, String msg) {
path = p;
message = msg;
}
public void run() {
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleClient).await();
for (Node node : nodes.getNodes()) {
MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(googleClient, node.getId(), path, message.getBytes()).await();
if (result.getStatus().isSuccess()) {
Log.v("myTag", "Message: {" + message + "} sent to: " + node.getDisplayName());
}
else {
// Log an error
Log.v("myTag", "ERROR: failed to send Message");
}
}
}
}
}
you should add MESSAGE_RECEIVED action into the manifest.xml rather than BIND_LISTENER or DATA_CHANGED (DATA_CHANGED only used for onDataChange), as for high version of gms e.g. 9.6.1
<service android:name=".MyWearService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
<data android:scheme="wear" android:host="*"
android:path="/sensor_test" />
</intent-filter>
</service>
Your .ListenerService-declaration in your Mobile-AndroidManifest must be within the <application> tag. In your code it's outside.
Hope this fixes it.
GCM is generating token when the build grader is com.google.gms:google-services:1.4.0-beta3 but when I change it to com.google.gms:google-services:1.3.0-beta1 it stops generating the "token.
When I am using 1.4.0-beta3" I set "com.google.android.gms:play-services-gcm:8.1.0" in build.gradle(app)
I have refered google document.
Can someone help me figure out where I am going wrong?
Here is my source code:
1)Build.gradle(project):
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath 'com.google.gms:google-services:1.3.0-beta1'
//classpath 'com.google.gms:google-services:1.4.0-beta3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
2)Here is build.gradle(app):
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
repositories {
maven { url 'https://maven.fabric.io/public' }
}
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.yembrace.android.app"
minSdkVersion 21
targetSdkVersion 21
maxSdkVersion 22
versionCode 4
versionName "1.0.3"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile 'com.google.android.gms:play-services-plus:7.5.0'
compile "com.google.android.gms:play-services-gcm:7.5.0"
// compile 'com.google.android.gms:play-services-plus:8.1.0'
// compile "com.google.android.gms:play-services-gcm:8.1.0"
compile 'com.mcxiaoke.volley:library:1.0.19'
compile 'com.android.support:recyclerview-v7:23.1.0'
compile 'de.hdodenhof:circleimageview:1.2.1'
compile 'com.android.support:cardview-v7:23.1.0'
//beacons sdk
compile 'com.estimote:sdk:0.8.8#aar'
compile 'com.github.clans:fab:1.6.2'
//Cards
compile 'com.github.gabrielemariotti.cards:cardslib-cards:2.1.0'
compile('com.crashlytics.sdk.android:crashlytics:2.5.2#aar') {
transitive = true;
}
}
3)Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yembrace.android.app">
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="com.yembrace.yembarce.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<permission
android:name="com.yembrace.android.app.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<application
android:name=".AppController"
android:allowBackup="true"
android:icon="#drawable/app_logo"
android:label="#string/app_name"
android:theme="#style/AppCompatTheme"
android:screenOrientation="portrait">
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<!-- - Receivers -->
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.yembrace.yembarce" />
</intent-filter>
</receiver>
<receiver android:name=".Receivers.BeaconReceiver">
<intent-filter>
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
</intent-filter>
</receiver>
<receiver android:name=".Receivers.LocationReceiver">
<intent-filter>
<action android:name="android.location.PROVIDERS_CHANGED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- Services -->
<service
android:name=".Services.MyGcmListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".Services.MyInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name=".Services.RegistrationIntentService"
android:exported="false" />
<service android:name=".Services.BeaconService" />
<service
android:name="com.estimote.sdk.service.BeaconService"
android:exported="false" />
<action android:name="android.location.PROVIDERS_CHANGED" />
<service
android:name=".Services.LocationService"
android:exported="false" />
<!-- Activities -->
<!-- Launcher Activity -->
<activity
android:name=".Activities.Launcher"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Login Activity -->
<activity
android:name=".Activities.LoginActivity"
android:label="#string/titleActivityLogin"
android:theme="#style/ThemeOverlay.MyNoTitleActivity" />
<activity
android:name=".Activities.MainActivity"
android:label=""
/>
<activity
android:name=".Activities.ShopActivity"
android:label=""
/>
<activity
android:name=".Activities.ItemActivity"
android:label=""
/>
<activity
android:name=".Activities.ProfileActivity"
android:label="#string/titleActivityProfile"
/>
<activity
android:name=".Activities.AboutActivity"
android:label="#string/titleActivityAbout"
/>
<meta-data
android:name="io.fabric.ApiKey"
android:value="9e91d69acd5e717118f65608d8b4bae54dd4ab43" />
<!--<activity
android:name=".Activities.CheckoutActivity"
android:label="#string/title_activity_checkout"
android:theme="#style/AppTheme"></activity>-->
</application>
</manifest>
4)RegistrationIntentService.java
public class RegistrationIntentService extends IntentService {
private static final String TAG = "RegIntentService";
private static final String[] TOPICS = {"global"};
private SharedPreferences sharedPreferences = AppController.getAppContext().getSharedPreferences("app_pref", MODE_PRIVATE);
public RegistrationIntentService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
try {
// [START register_for_gcm]
// Initially this call goes out to the network to retrieve the token, subsequent calls
// are local.
// [START get_token]
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
// [END get_token]
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(token);
// Subscribe to topic channels
subscribeTopics(token);
// You should store a boolean that indicates whether the generated token has been
// sent to your server. If the boolean is false, send the token to your server,
// otherwise your server should have already received the token.
sharedPreferences.edit().putBoolean(Config.SENT_TOKEN_TO_SERVER, true).apply();
// [END register_for_gcm]
} catch (Exception e) {
Log.d(TAG, "Failed to complete token refresh", e);
// If an exception happens while fetching the new token or updating our registration data
// on a third-party server, this ensures that we'll attempt the update at a later time.
sharedPreferences.edit().putBoolean(Config.SENT_TOKEN_TO_SERVER, false).apply();
}
// Notify UI that registration has completed, so the progress indicator can be hidden.
Intent registrationComplete = new Intent(Config.REGISTRATION_COMPLETE);
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}
/**
* Persist registration to third-party servers.
*
* Modify this method to associate the user's GCM registration token with any server-side account
* maintained by your application.
*
* #param token The new token.
*/
private void sendRegistrationToServer(final String token) {
// Add custom implementation, as needed.
Log.d("TAG","GCM Token "+token);
StringRequest stringRequest = new StringRequest(Request.Method.POST,
Config.user_gcm_register,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("TAG",response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("TAG",error.toString());
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> params = new HashMap<>();
//params.put("Authorization", Config.authorization);
return params;
}
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
Log.d("TAG","user Id "+sharedPreferences.getString("userID","null")+",GCM:"+token);
params.put("PublicUserID",sharedPreferences.getString("userID","null"));
params.put("GCMRegistrationToken",token);
return params;
}
};
AppController.getInstance().addToRequestQueue(stringRequest);
}
/**
* Subscribe to any GCM topics of interest, as defined by the TOPICS constant.
*
* #param token GCM token
* #throws IOException if unable to reach the GCM PubSub service
*/
// [START subscribe_topics]
private void subscribeTopics(String token) throws IOException {
GcmPubSub pubSub = GcmPubSub.getInstance(this);
for (String topic : TOPICS) {
pubSub.subscribe(token, "/topics/" + topic, null);
}
}
// [END subscribe_topics]
}
5) Here is where I call GCM:
private void GCMRegister() {
Log.d("TAG","In gcm rregister in login");
mRegistrationBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean sentToken = sharedPreferences.getBoolean(Config.SENT_TOKEN_TO_SERVER, false);
if (sentToken) {
Log.d(TAG, "register");
} else {
Log.d(TAG, "token error");
}
}
};
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
I was able to solve this problem by adding following in my manifest file:
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>