I followed twitter_login plugin guide but I always get error. Specifically the TwitterLoginStatus.error is true and the authentication process ends of course. Here is my code:
Future signInWithTwitter() async {
// Create a TwitterLogin instance
final twitterLogin = TwitterLogin(
apiKey: 'xxxxxxxxx',
apiSecretKey: 'xxxxxxxxxxxxxxxxxxxx',
redirectURI: 'my-app://');
final authResult = await twitterLogin.login();
switch (authResult.status) {
case TwitterLoginStatus.loggedIn:
// success
print("succ");
return await FirebaseAuth.instance.signInWithCredential(
TwitterAuthProvider.credential(
accessToken: authResult.authToken!,
secret: authResult.authTokenSecret!,
),
);
break;
case TwitterLoginStatus.cancelledByUser:
// cancel
print("cancel");
break;
case TwitterLoginStatus.error:
// error
print("error");
break;
default:
print("def");
break;
}
}
AndroidManifest.xml:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "example://gizmosā -->
<!-- Registered Callback URLs in TwitterApp -->
<data android:scheme="my-app" /> <!-- host is option -->
</intent-filter>
And also I have included the updated callback in the Twitter Developer portal:
Lastly I use twitter_login: ^4.1.0 but I have also tried with 4.0.1
Related
So I have a slightly weird setup where I redirect all routes where I need dynamic routing to index.tsx and use react-router-dom to handle those routes Client-side. I mainly had to do this because it seems that when exporting Next.js sites to a static site, Next.js generates pages for each route, so I can't generate new routes in Javascript.
However, this setup doesn't seem work properly when using react-router-dom's <Navigate /> component. For example,
// index.tsx
const Home: FC = () => {
// Currently going to generate the room id locally, but we
// should do this server side so that we can guarantee uniqueness.
return (
<Router>
<Routes>
<Route path="/" element={<RedirectToMain />} />
<Route path="/:roomId" element={<Main />} />
</Routes>
</Router>
);
}
const RedirectToMain: FC = () => {
const generatedRoomId = Array(5)
.fill(null)
.map(x => alphabet[Math.floor(26 * Math.random())])
.join('');
console.log('navigating');
return <Navigate to={generatedRoomId} />;
}
const Main: FC = () => {
const { roomId } = useParams();
console.log(roomId);
// We must wait for roomId to load before running.
if (!roomId || roomId.length === 0) {
return <></>;
}
return (
<WebSocketProvider roomId={roomId}>
<MinesAppBar url={`http://mineswpr.io/${roomId}`} />
<Board />
</WebSocketProvider>
);
};
When running this locally with yarn next dev, it redirects to localhost:3000/ABCDE and then the url changes back to localhost:3000/. When running this as a static site which is setup to redirect all traffic to /index.html, it seems to constantly call <Navigate />.
How can I fix this issue?
I created a Dynamic link through createDynamicLink that is inside the class DynamicLinkService, after this I use retrieveDynamicLink for the part of reading the link that is opened from the android browser, but it prints that it is null, therefore it does not enter the if and does not push to another route inside the if
class DynamicLinkService {
Future<void> retrieveDynamicLink(BuildContext context) async {
try {
final PendingDynamicLinkData? data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri? deepLink = data?.link;
print("deepLink: $deepLink");
if (deepLink != null) {
print("deepLink If: $deepLink");
String deepLinks = deepLink.toString();
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => linkInvitacionScreen(deepLinks)));
}
} catch (e) {
print(e.toString());
}
}
Future<String> createDynamicLink(String groupID) async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://notforget.page.link/',
link: Uri.parse(
'https://notforget.com/groupid?$groupID'),
androidParameters: const AndroidParameters(
packageName: 'com.example.not_forget_flutter',
minimumVersion: 1,
),
);
final ShortDynamicLink shortDynamicLink =
await FirebaseDynamicLinks.instance.buildShortLink(parameters);
final Uri shortUrl = shortDynamicLink.shortUrl;
print(shortUrl);
return shortUrl.toString();
}
}
intent filter of AndroidManifest
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="#style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- Deep linking -->
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="notforget.page.link" />
<data android:scheme="https" />
</intent-filter>
</activity>
i tried various solutions but none led me to get a value in deeplink, what am i doing wrong?, thanks.
Replace Your Host From android:host="notforget.page.link" To android:host="notforget.page.link"
I updated the Firebase messaging code in my app which has changed a lot with the recent version. A nice thing is the possibility to see the push message also in the foreground, using local notifications. Now everything works for me when the app is closed, when the app is in the background. When the app is in the foreground it works on iOS but not Android.
I followed the instructions. Added custom channel on Manifest.
I'll give you my code. If you tell me where I went wrong I'm grateful.
The Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.carlosacchetti.push_notification_example">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="push_notification_example"
android:icon="#mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="#style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="#drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- <intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter> -->
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<!-- A custom Android Notification Channel to deliver FCM notifications on a non-default channel -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="high_importance_channel" />
</application>
</manifest>
The "main"
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
print('Handling a background message ${message.messageId}');
}
/// Create a [AndroidNotificationChannel] for heads up notifications
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.max,
);
/// Initialize the [FlutterLocalNotificationsPlugin] package.
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// Set the background messaging handler early on, as a named top-level function
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
runApp(MyApp());
}
The "HomePage"
#override
void initState() {
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage message) {
if (message != null) {
// Navigator.pushNamed(context, '/message',
// arguments: MessageArguments(message, true));
}
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification?.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: 'launch_background',
),
));
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
// Navigator.pushNamed(context, '/message',
// arguments: MessageArguments(message, true));
});
super.initState();
}
Where is the error that it does not allow foreground notifications in Android?
I am building a home automation project that has a fire sensor that will write to Firebase Database if there is a fire detected, then from that point I need to make an alarm for the user.
I managed to trigger a notification from Firebase cloud functions, but that's not exactly what I want.
What I want is to make a full-screen notification to the user with a custom sound something like a phone alarm or a what's app call when there is a fire alarm -change in the database-.
I tried as a Top level function with no error while running my application:
firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print('onMessage: $message');
toast3('asdasdsawwwww $message');
setMessage(message);
},
onLaunch: (Map<String, dynamic> message) async {
print('onLaunch: $message');
setMessage(message);
},
onResume: (Map<String, dynamic> message) async {
print('onResume: $message');
setMessage(message);
},
onBackgroundMessage: myBackgroundMessageHandler);
print('onMessage:12qew11');
firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound: true, badge: true, alert: true),
);
}
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
print('HEREE');
final assetsAudioPlayer = AssetsAudioPlayer();
assetsAudioPlayer.open(
Audio("assets/audio/alarm.mp3"),
);
return Fluttertoast.showToast(
msg: 'done background:))))$message',
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 4,
backgroundColor: Colors.redAccent,
textColor: Colors.white,
fontSize: 15.0);
}
My Firebase function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().functions);
var fireDatabase;
exports.myFirstCloudFun = functions.database.ref('/usersData/{userID}/Fire').onUpdate(async (event, context) => {
const uidGotten = context.params.userID;
const fireData = event.after.val()
console.log('data changed in fire is' + fireData + 'userID is ' + uidGotten);
const usereIdTokens = await admin
.firestore()
.collection(uidGotten)
.doc('userTokens')
.get();
console.log('Tokens to try are' + usereIdTokens.data);
var tokens = usereIdTokens.data().user_all_tokens;
var payload = {
notification: {
title: 'Push Title',
body: 'Push Body' + fireData,
sound: 'default',
},
data: {
push_key: 'Fire Value Is',
key1: "fireData is " + fireData,
},
};
tokens.forEach.toString().trim;
console.log('Tokens to send are ' + tokens[1] + ' ////// ' + tokens);
try {
const response = await admin.messaging().sendToDevice(tokens, payload);
console.log('Notification sent successfully');
} catch (err) {
console.log(err);
}
});
My Application.kt
package com.eghubs.eg_home_hubs
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
public class Application: FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
FlutterFirebaseMessagingService.setPluginRegistrant(this)
}
override fun registerWith(registry: PluginRegistry) {
FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
}
}
My FirebaseCloudMessagingPluginRegistrant.kt
package com.eghubs.eg_home_hubs
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin
class FirebaseCloudMessagingPluginRegistrant {
companion object {
fun registerWith(registry: PluginRegistry) {
if (alreadyRegisteredWith(registry)) {
return;
}
FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"))
}
fun alreadyRegisteredWith(registry: PluginRegistry): Boolean {
val key = FirebaseCloudMessagingPluginRegistrant::class.java.name
if (registry.hasPlugin(key)) {
return true
}
registry.registrarFor(key)
return false
}
}
}
My AndroidManifest is :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.eghubs.eg_home_hubs">
<uses-permission android:name="android.permission.ACCESS_CORSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET"/>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here.
android:name="io.flutter.app.FlutterApplication"
android:name="androidx.multidex.MultiDexApplication"
-->
<application
android:name=".Application" <!-- here is the change-->
android:label="EG HomeHubs"
android:allowBackup="false"
android:icon="#mipmap/ic_launcher">
tools:replace="android:allowBackup">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
android:showWhenLocked="true"
android:turnScreenOn="true">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="#style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="#drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter> <!-- Noti:this is for cloud messiging -->
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
but I get nothing when the application is not opened in the background, why onBackgroundMessage function is not called?
My question is how can I achieve that what's an app call or something of that kind?
OR Is there any better way to do this, some other way to achieve that fire alarm functionality in my project from the firebase database change?
EDIT: My app/build.gradle
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
//GradleException
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
packagingOptions {
exclude 'META-INF/services/javax.annotation.processing.Processor'
}
compileSdkVersion 30
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.eghubs.eg_home_hubs"
minSdkVersion 21
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
// multiDexEnabled true
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
debug {
minifyEnabled true
shrinkResources true
}
}
}
flutter {
source '../..'
}
dependencies {
implementation 'com.google.firebase:firebase-analytics'
implementation platform('com.google.firebase:firebase-bom:26.0.0')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// implementation 'androidx.multidex:multidex:2.0.1' //with androidx libraries
implementation'com.google.firebase:firebase-messaging:21.0.1'
}
apply plugin: 'com.android.application'
// Add this line
apply plugin: 'com.google.gms.google-services'
My android/build.gradle:
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.google.gms:google-services:4.3.4'
//classpath 'com.android.tools.build:gradle:3.5.3' //todo rollback this
classpath 'com.android.tools.build:gradle:4.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
I have some solutions for solving this problem.
Solution 1:
The first thing you have to do is to check if onBackgroundMessage is supported in iOS or not.
And in Android, you have to turn on the Allow running in background option.
Solution 2:
Create a high importance channel through the flutter_local_notifications package.
flutter_local_notifications package link: https://pub.dev/packages/flutter_local_notifications
Solution 3:
Create a new file App.java inside folder java/com/yourdomain
package com.yourdomain;
import io.flutter.app.FlutterApplication;
public class App extends FlutterApplication {
#Override
public void onCreate() {
super.onCreate();
}
}
Then, inside AndroidManifest.xml file, add android:name=".App"
<application
android:name=".App"
...
>
After that rebuild the application and the notifications will work correctly even when the app is terminated or killed.
On Android, for your onBackgroundMessage to be called when the app is in the background the FCM message must be a data message without notification, look here: https://firebase.google.com/docs/cloud-messaging/android/receive
Also when the device is sleeping, to receive the messages without much delay you should disable the battery optimization, look at this: https://developer.android.com/training/monitoring-device-state/doze-standby
Alright.
Since update 8.0.0-dev.1
we can get onBackgroundMessage by default without any need for these installation process
NEW: FirebaseMessaging.onBackgroundMessage() Sets a background message
handler to trigger when the app is in the background or terminated.
I'm trying to use FCM messaging and keep getting this error.
E/FlutterFcmService( 3684): Fatal: failed to find callback
Below is the code I've used to setup.
static Future<void> messagePiper(
Map<String, dynamic> message,
FilteredMap<String, ChatMessage> globalChatEntryMap,
FilteredMap<String, ChatMessage> gameChatEntryMap,
Subject<List<ChatMessage>> globalChatSubject,
Subject<List<ChatMessage>> gameChatSubject,
Map<String, Player> _playerMap) async {
final Map<String, dynamic> data = message['data'];
if (data.containsKey('name')) {
final msg = ChatMessage.fromMap(data);
globalChatEntryMap.putIfAbsent(msg.id, () => msg);
globalChatSubject.add(globalChatEntryMap.values.toList());
} else {
final msg = GameChatMessage.fromMap(data);
final chat = ChatMessage.fromGlobalChatMessage(
msg,
_playerMap[msg.pId].name,
_playerMap[msg.pId].imageUrl,
);
print('chat: $chat');
gameChatEntryMap.putIfAbsent(msg.id, () => chat);
print('_gameChatEntryMap : $gameChatEntryMap');
gameChatSubject.add(gameChatEntryMap.values.toList());
}
return Future<void>.value();
}
is the callback passed in to FirebaseMessaging configuration.
final FirebaseMessaging _fm = FirebaseMessaging();
#override
void initState() {
_fm.configure(
onMessage: (Map<String, dynamic> message) async {
print('onMessagee : $message');
return Utils.messagePiper(
message,
_globalChatEntryMap,
_gameChatEntryMap,
_globalChatSubject,
_gameChatSubject,
_playerMap);
},
onLaunch: (Map<String, dynamic> message) async {
print('onLaunch : $message');
return Utils.messagePiper(
message,
_globalChatEntryMap,
_gameChatEntryMap,
_globalChatSubject,
_gameChatSubject,
_playerMap);
;
},
onResume: (Map<String, dynamic> message) async {
print('onResume : $message');
return Utils.messagePiper(
message,
_globalChatEntryMap,
_gameChatEntryMap,
_globalChatSubject,
_gameChatSubject,
_playerMap);
;
},
onBackgroundMessage: null);
....
Java configuration file
package io.flutter.plugins;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;
public class Application extends FlutterApplication implements PluginRegistrantCallback {
#Override
public void onCreate() {
super.onCreate();
FlutterFirebaseMessagingService.setPluginRegistrant(this);
}
#Override
public void registerWith(PluginRegistry registry) {
GeneratedPluginRegistrant.registerWith(registry);
}
}
dependency versions
random_string: 0.0.2
firebase_auth: ^0.14.0+5
firebase_database: ^3.0.7
provider: 3.0.0
rxdart: ^0.22.2
collection: ^1.14.11
audioplayers: ^0.13.2
firebase_admob: ^0.5.5
connectivity: ^0.4.4
firebase_messaging: ^5.1.6 # tried with several different versions
I tried with several firebase_messaging versions but couldn't find a fix.
Appreciate any help to solve this issue.
This error message is coming from startBackgroundIsolate which is used for allowing handling background messages.
If you don't want to handle background messages then you can safely ignore this error message. Otherwise, you need to set up a callback for handling background messages as described here
If your callback is not executed when clicking on the notification then it's because you didn't set click_action property of the message to FLUTTER_NOTIFICATION_CLICK
Are you sending FCM using the web, not FCM console?
make sure the post request is correct on your backend. I'm using Laravel
$response = Http::withHeaders([
'Content-Type' => 'application/json',
'Authorization'=> 'key='. $token,
])->post($url, [
'notification' => [
'body' => $request->summary,
'title' => $request->title,
'image' => request()->getHttpHost().$path,
],
'priority'=> 'high',
'data' => [
'click_action'=> 'FLUTTER_NOTIFICATION_CLICK',
'status'=> 'done',
],
'to' => '/topics/all'
]);
You should declare a backgroundMessageHandler function that is outside a class or as a static function, in order to be reached from outside, and then you pass this function to fbm.configure:
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
print('on background $message');
}
fbm.configure(
onMessage: (msg) {
print(msg);
return;
},
onLaunch: (msg) {
print(msg);
return;
},
onResume: (msg) {
print(msg);
return;
},
onBackgroundMessage: myBackgroundMessageHandler
);
Also open your_project_folder/android/app/source/AndroidManifest.xml and paste this XML code after existing intent-filter code of your main Activity:
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
The result will be similar to the following code:
<activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="#style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
In Application class use the below code
previously it was GeneratedPluginRegistrant.registerWith(registry);,
replace it with
FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin;
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;
public class Application extends FlutterApplication implements PluginRegistrantCallback {
#Override
public void onCreate(){
super.onCreate();
FlutterFirebaseMessagingService.setPluginRegistrant(this);
}
#Override
public void registerWith(PluginRegistry registry){
FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
}
}
When I was trying to send a notification from the firebase console just to test my app receives notifications, I also encountered the same error. Make sure you kill the app on your emulator so it is not running in the background. And now try sending a notification from the firebase console, wait for a couple of seconds and you should see it. This worked for me.