How can i use broadcast receiver/intent to open flutter android app when receive firebase message.
Implment FirebaseMessagingService and start Main activity from onMessageReceived:
public class FirebaseMsgService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//...
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
and also in MainActivity you may want to unlock device:
public class MainActivity extends FlutterActivity {
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
Window window = this.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
}
The answer provided by #Develocode777 will work until android 9. From android 10, this behavior is not allowed anymore. You can learn more about it in this page, Restrictions on starting activities from the background.
If you are planning to show a notification, and upon clicking the notification you want to open the app, then it it will work normally, but opening the app without no user interaction, not allowed in Android 10 and above.
Related
Having android sdk which intercept the push notification, and has been using notification trampoline to further open the end activity. In the case of deeplink the app who uses this sdk will open the configured deeplink handler activity.
Snippet for the trampoline:
public class NotificationTrampolineReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final PendingResult asyncResult = goAsync();
ExecutorService executor = Executors.newSingleThreadExecutor();
asycTask(executor, new Runnable() {
#Override
public void run() {
String urlStr = getStringExtra(intent, PUSH_URL);
if (urlStr != null) {
var intent2: Intent = Intent(Intent.ACTION_VIEW, Uri.parse(urlStr));
if (intent2 != null) {
intent2.addFlags(FLAG_ACTIVITY_NEW_TASK);
intent2.addFlags(FLAG_ACTIVITY_BROUGHT_TO_FRONT);
context.startActivity(intent2);
logAnalytics(intent, Message.MessageAction.OPEN);
}
}
asyncResult.finish();
}
});
}
void asycTask(ExecutorService executor, final Runnable task) {
try {
executor.execute(task);
} catch (Throwable ex) {}
}
}
The notification trampolines is not working in Android 12 anymore.
The notification trampolines is needed in the sdk to intercept the click and do something like to log analytics event; closing the notification drawer when clicking at the Action button on the notification, etc. And this sdk does not know what activities the app may configure to handle the deeplinks.
Using a dummy activity to replace the trampoline would work, but not feel right, i.e. open the activity and inside to open another one then finish this one.
When android 12 puts restriction on the notification tramoline, does it suggest a replacement for the use case like the one here? Haven't find one.
What is the suggested new solution for intercepting the push notification tap first and then open the activity?
You are better off launching an Activity directly from the Notification. The Activity could then do the analytics and figure out what Activity needs to be launched and then delegate to that. As an alternative, the launched Activity could send the broadcast Intent to your BroadcastReceiver which could do the work.
NOTE: If you launch an Activity directly from a Notification, that is not a trampoline. The trampoline occurs when you launch a Service or a BroadcastReceiver directly from the Notification and that component then launches an Activity. The idea is that the user needs to be in control of what pops onto his screen. If he taps a notification, he expects that something will appear on his screen, if your Service launches an Activity, that can happen at any time and could possibly interrupt him.
I have no idea how to pass a parameter from MainActivity.cs
this code from App.cs
protected override void OnResume(int notificationId)
{
MainPage = new AppShell(notificationId);
}
I plan to pass a number in the "notificationId" parameter. To find a row in the database by "notificationId".
If you're integrating push notification(e,g Azure notification hubs) into your application , OnResume is not the appropriate method to handle this .
Actually every push notification kit has its own trigger method when receiving notification (or tapping on the notification alert) .
For example , we can handle the notification in method OnPushNotificationReceived with Azure notification .
// Set the delegate for receiving messages
NotificationHub.SetListener(new SampleNotificationListener());
// The notification listener implementation
public class SampleNotificationListener : Java.Lang.Object, INotificationListener
{
public void OnPushNotificationReceived(Context context, INotificationMessage message)
{
Console.WriteLine($"Message received with title {message.Title} and body {message.Body}");
}
}
Refer to https://github.com/Azure/azure-notificationhubs-xamarin#getting-started-with-xamarinandroid.
Then we can use Messaging Center to send the data to Forms project if you want .
Something like
//Android
public void OnPushNotificationReceived(Context context, INotificationMessage message)
{
MessagingCenter.Send<object,int >(this, "Hi",notificationId);
}
//Forms App.cs
MessagingCenter.Subscribe<object,int> (this, "Hi", (sender,id) =>
{
MainPage = new AppShell(id);
});
How to Get both Notification and data when app is background in android.
When app is foreground than get both Notification and data.
But when app in background than get only data.
I want Get both Notification and data when app is background.
As i searched it's not possible.
you can pass Notification parameters to data and get them in
#Override
public void onMessageReceived(RemoteMessage remoteMessage){
createNotification(remoteMessage.getData());
}
private void createNotification(Map<String, String> data) {
....
NotificationCompat.Builder mNotificationBuilder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_icon)
.setContentTitle(data.get("title"))
.setContentText(data.get("body"))
}
I am trying to use Google Sign-In for my android app from here.
I am able to log-in succesfully with the google account & able to fetch all the details. However, when ever I try to logout it fails with following error :
java.lang.IllegalStateException: GoogleApiClient is not connected yet.
I have read many answers suggesting to create googleClientApi object inside onCreate() and that's what I am doing.I have added callbacks for connected and suspended but the connect never goes into suspended mode.
Following is my code snippet :
public static void doInit(Context ctx, FragmentActivity fragmentActivity) {
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(
GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(ctx)
.enableAutoManage(fragmentActivity , googleAuth)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.addConnectionCallbacks(googleAuth)
.build();
}
public static Intent doGoogleLogIn() {
return Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
}
public static boolean doGoogleLogOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
}
});
return true;
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// An unresolvable error has occurred and Google APIs (including Sign-In) will not
// be available.
Log.d("Signin", "onConnectionFailed:" + connectionResult);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
System.out.println("Connected...");
}
#Override
public void onConnectionSuspended(int i) {
System.out.println("Suspened....");
}
The only thing that is doubtful to me is, when I login and create googleApiClient object, its created from different activity that the one which I am using for logout. I don't suspect this is the reason because when the activity loaded, the isConnected on googleApiClient is returning true. However, the moment I do some UI action(Click on Logout), it starts returning false.
Primary requirement was to login and logout from different activities.
Finally I managed to make it work.
The actual cause of the error is "enableAutoManage" invocation at the time of Building Client object.
The API doc here suggests that it would automatically do the life cycle management by calling methods on onStart & onStop of the activity.
Therefore, if you want to use the same object across different activities then you should avoid calling "enableAutoManage" and invoke apiObject.connect(preferably in onStart of activity) and apiObject.disconnect() or logout (preferably in onStop of activity) manually.
The push notification clears when the user taps on the notification to open app. However if the user goes and opens the app, the push notification is still there. How can I get rid of the notification? I can't seem to find anywhere in the documentation that addresses this.
Thanks a lot in advance
I did some digging as I too had this problem, and it looks like a bug in the Push Plugin. Basically they added the removal code to the pause event instead of the resume event.
You just have to change the code in src/android/com/plugin/gcm/PushPlugin.java
from:
#Override
public void onPause(boolean multitasking) {
super.onPause(multitasking);
gForeground = false;
final NotificationManager notificationManager = (NotificationManager) cordova.getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancelAll();
}
#Override
public void onResume(boolean multitasking) {
super.onResume(multitasking);
gForeground = true;
}
to:
#Override
public void onPause(boolean multitasking) {
super.onPause(multitasking);
gForeground = false;
}
#Override
public void onResume(boolean multitasking) {
super.onResume(multitasking);
gForeground = true;
final NotificationManager notificationManager = (NotificationManager) cordova.getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancelAll();
}
This will create a more standard behaviour, where the notifications will be removed on app resume (instead of on pause). Note though, I haven't fully tested the effects on the internal app messages yet, which may require more changes.