Chrisco
Chrisco

Reputation: 43

Load Xamarin Forms page from android notification

I am trying to load a Xamarin Forms page from an Android Notification. I am really lost on the android side of this, and most of my code has been pieced together from tutorials and blog posts. However nothing really seems to cover exactly this scenario.

I have implemented a very simple interface with dependency service to create the notification with an intent...

[assembly: Xamarin.Forms.Dependency(typeof(QuoteNotification))]

namespace QuoteApp.Droid
{

    class QuoteNotification : IQuoteNotification
    {


        public void Notify(string title, string message)
        {

            //type needs to be derived from java, not xamarin.forms
            Intent LoadPostPage = new Intent(Forms.Context, typeof(DroidToForms));
            const int pendingIntentId = 0;
            PendingIntent pendingIntent =
                PendingIntent.GetActivity(Forms.Context, pendingIntentId, LoadPostPage, PendingIntentFlags.OneShot);

            Notification.Builder builder = new Notification.Builder(Forms.Context)
                .SetContentIntent(pendingIntent)
                .SetAutoCancel(true)

                     .SetContentTitle(title)
                     .SetContentText(message)
                     .SetSmallIcon(Resource.Drawable.icon);

            // Build the notification:
            Notification notification = builder.Build();

            // Get the notification manager:
            NotificationManager notificationManager =
                Forms.Context.GetSystemService(Context.NotificationService) as NotificationManager;

            // Publish the notification:
            const int notificationId = 0;
            notificationManager.Notify(notificationId, notification);
        }
    }
}

this calls an activity -

namespace QuoteApp.Droid
{
    [Activity(Label = "QuoteApp", MainLauncher = true)]
    class DroidToForms : Activity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            StartActivity(typeof(XFPostPage));
            //Xamarin.Forms.Application.Current.MainPage.Navigation.PushAsync(new QuoteApp.PostPage());

        }
    }
}

which in turn calls this forms page, all the code here has been in Xamarin.Android project

namespace QuoteApp.Droid
{



        /// <summary>
        /// This is a Xamarin.Forms screen. It MUST:
        /// * inherit from ANdroidActivity
        /// * call Forms.Init()
        /// * use LoadApplication()
        /// </summary>
        [Activity(Label = "XFPostPage", MainLauncher = true) ]
        public class XFPostPage : Xamarin.Forms.Platform.Android.FormsApplicationActivity
        {
            protected override void OnCreate(Bundle bundle)
            {
                base.OnCreate(bundle);

                Xamarin.Forms.Forms.Init(this, bundle);

            //LoadApplication( new App() ); //how do i send to PostPage.xaml ??

            Xamarin.Forms.Application.Current.MainPage.Navigation.PushAsync(new QuoteApp.PostPage());
        }
        }
    }

this gives the following error in logcat

07-04 17:51:44.494  7668  7668 E AndroidRuntime: Caused by: android.runtime.JavaProxyThrowable: System.NullReferenceException: Object reference not set to an instance of an object
07-04 17:51:44.494  7668  7668 E AndroidRuntime:   at QuoteApp.Droid.XFPostPage.OnCreate (Android.OS.Bundle bundle) [0x00016] in <ab64801c0fb24acb8457c1d1202cc143>:0
07-04 17:51:44.494  7668  7668 E AndroidRuntime:   at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState) [0x0000f] in <d855bac285f44dda8a0d8510b679b1e2>:0
07-04 17:51:44.494  7668  7668 E AndroidRuntime:   at (wrapper dynamic-method) System.Object:2780fa42-5931-40d3-8d14-a642f1a3025c (intptr,intptr,intptr)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at md543d03747be5a5b03a21a2a23b8ba191a.XFPostPage.n_onCreate(Native Method)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at md543d03747be5a5b03a21a2a23b8ba191a.XFPostPage.onCreate(XFPostPage.java:29)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.app.Activity.performCreate(Activity.java:6237)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.app.ActivityThread.-wrap11(ActivityThread.java)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:102)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:148)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:5417)
07-04 17:51:44.494  7668  7668 E AndroidRuntime:        ... 3 more

I have tried a bunch of different ideas all with different runtime errors, my understanding of the Xamarin.Android workings are very limited. eventually i will be using the notification with AlarmManager and further information will be sent to PostPage.Xaml. At the moment i'm just lost at exactly where this is going wrong though?!

Any Help would be hugely appreciated, thanks in advance.

Upvotes: 2

Views: 4158

Answers (2)

Chrisco
Chrisco

Reputation: 43

I ended up using OnNewIntent in MainActivity.

there is some excellent information here Processing notifications in Xamarin Forms Android

My Code ended up looking like this.

Call the dependency service to get the android implmentation

DependencyService.Get<IQuoteNotification>().Notify("words",SelectedQuote.FixedTitle  , SelectedQuote.Id);

Which builds notification with the Intent:

  class QuoteNotification : IQuoteNotification
    {


        public void Notify(string title, string message, int postIndex)
        {

            //type needs to be derived from java, not xamarin.forms
            Intent LoadPostPage = new Intent(Forms.Context, typeof(MainActivity));
            LoadPostPage.PutExtra("NotificationTrue", true);
            LoadPostPage.PutExtra("PostID", postIndex);
            const int pendingIntentId = 0;
            PendingIntent pendingIntent =
                PendingIntent.GetActivity(Forms.Context, pendingIntentId, LoadPostPage, PendingIntentFlags.OneShot);
            

            Notification.Builder builder = new Notification.Builder(Forms.Context)
                    .SetContentIntent(pendingIntent)
                    .SetAutoCancel(true)
                    .SetContentTitle(title)
                    .SetContentText(message)
                    .SetSmallIcon(Resource.Drawable.icon);

            // Build the notification:
            Notification notification = builder.Build();

            // Get the notification manager:
            NotificationManager notificationManager =
                Forms.Context.GetSystemService(Context.NotificationService) as NotificationManager;

            // Publish the notification:
            const int notificationId = 0;
            notificationManager.Notify(notificationId, notification);
        }
    }

then Override OnNewIntent in MainActivity. If the intent is not Built by my QuoteNotification class then send -1 as PostID

        protected override void OnNewIntent(Intent intent)
    {
        if (intent.HasExtra("NotificationTrue")){
            LoadApplication(new App(intent.GetIntExtra("PostID", -1)));
            //Xamarin.Forms.Application.Current.MainPage.Navigation.PushAsync(new QuoteApp.PostPage());
        }
        base.OnNewIntent(intent);
    }

Then in App.Xaml.cs add some logic to navigate to the correct page

public partial class App : Application
{
    public App(int PostId = -1)
    {
        InitializeComponent();

        if (PostId >= 0)
        {
            MainPage = new NavigationPage(new PostPage(PostId));
        }
        else
            MainPage = new NavigationPage(new MainPage());

Upvotes: 2

Grace Feng
Grace Feng

Reputation: 16652

Problem is with your code Intent LoadPostPage = new Intent(Forms.Context, typeof(DroidToForms));.

For Android platform of XF project, it only has one Activity, which is MainActivity, or pages of XF are rendered based on this MainActivity.

So you may change you code like this:

Intent intent = new Intent(context, typeof(MainActivity));
intent.PutExtras(valuesForActivity);

PendingIntent resultPendingIntent = PendingIntent.GetActivity(Xamarin.Forms.Forms.Context, 0, intent, PendingIntentFlags.OneShot);

Then in your OnCreate method of MainActivity:

//navigate to the page of PCL
Xamarin.Forms.Application.Current.MainPage.Navigation.PushAsync(new PostPage());

At last, as @Pratik suggested, if you want to create a native page/ view for Android platform, use PageRenderer or ViewRenderer to do so.

Upvotes: 1

Related Questions