2

I am new to xamarin and Android so this question might be simple. However, I am trying to create a Broadcast receiver and an Intent Service following this article

I never seem to hit any of my debug points in the receiver or the intent service. I am not sure what is it that I am missing. This is my manifest:

<application android:label="gcc">
    <receiver android:name=".TrialBR" android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="gcc.gcc" />
        </intent-filter>
    </receiver>
    <service android:name=".MyIntentService" />
</application>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<permission android:name="gcc.gcc.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="gcc.gcc.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

I am not entirely sure about the package name. I am just following whatever is the package name in the android settings of the project. This is my receiver:

[BroadcastReceiver]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
public class TrialBR : BroadcastReceiver
{
    public override void OnReceive (Context context, Intent intent)
    {
        MyIntentService.RunIntentInService(context, intent);
        SetResult(Result.Ok, null, null);
        Toast.MakeText (context, "Received intent!", ToastLength.Short).Show ();
    }
} 

and this is my intent service:

[Service]
public class MyIntentService : IntentService
{
    static PowerManager.WakeLock sWakeLock;
    static object LOCK = new object();

    public static void RunIntentInService(Context context, Intent intent)
    {
        lock (LOCK)
        {
            if (sWakeLock == null)
            {
                // This is called from BroadcastReceiver, there is no init.
                var pm = PowerManager.FromContext(context);
                sWakeLock = pm.NewWakeLock(
                    WakeLockFlags.Partial, "My WakeLock Tag");
            }
        }

        sWakeLock.Acquire();
        intent.SetClass(context, typeof(MyIntentService));
        context.StartService(intent);
    }

    protected override void OnHandleIntent(Intent intent)
    {
        try
        {
            Context context = this.ApplicationContext;
            string action = intent.Action;

            if (action.Equals("com.google.android.c2dm.intent.REGISTRATION"))
            {
                HandleRegistration(context, intent);
            }
            else if (action.Equals("com.google.android.c2dm.intent.RECEIVE"))
            {
                HandleMessage(context, intent);
            }
        }
        finally
        {
            lock (LOCK)
            {
                //Sanity check for null as this is a public method
                if (sWakeLock != null)
                    sWakeLock.Release();
            }
        }
    }

    void HandleRegistration (Context context, Intent intent)
    {
        string senders = "123456789";
        Intent intent1 = new Intent("com.google.android.c2dm.intent.REGISTER");
        intent1.SetPackage("com.google.android.gsf");
        intent1.PutExtra("app", PendingIntent.GetBroadcast(context, 0, new Intent(), 0));
        intent1.PutExtra("sender", senders);
        context.StartService(intent1);
    }

    void HandleMessage (Context context, Intent intent)
    {
        string registrationId = intent.GetStringExtra("registration_id");
        string error = intent.GetStringExtra("error");
        string unregistration = intent.GetStringExtra("unregistered");
        Console.WriteLine ("Registration ID: " + registrationId);
    }
}

I would really appreciate if someone can point me in the right direction of what it is that I am doing wrong. I will really appreciate it.

Muqeet Khan
  • 2,094
  • 1
  • 18
  • 28

1 Answers1

0

I have published an answer regarding this question here: https://stackoverflow.com/a/29141884/2452682

But from a quick look from your solution, first of all you can remove those manual definitions from the manifest file, and place them in the code. this might be the reason you are not receiving push notifications, since I can see some differences between my generated manifest file and yours (the receiver looks completely different)

Anyway, I have copied just the android part of the implementation from my solution provided in the link:

1) In your shared project, create an Interface called IPushNotificationRegister

 public interface IPushNotificationRegister
{
    void ExtractTokenAndRegister();
}

This interface is used for fetching the push token and then send it to the server. this Token is unique per device.

2) In Your shared proejct, you should invoke ExtractTokenAndRegister (using your favourite IOC, I called it right after login).

Android Implementation:

Add Receivers for listening to events received by Google GCM service:

a) [BroadcastReceiver] [IntentFilter(new[] { Intent.ActionBootCompleted })] public class GCMBootReceiver : BroadcastReceiver { public override void OnReceive(Context context, Intent intent) { MyIntentService.RunIntentInService(context, intent); SetResult(Result.Ok, null, null); } }

b)

[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
    [assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
    [assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
    [assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
    [assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
    [assembly: UsesPermission(Name = "android.permission.INTERNET")]

namespace Consumer.Mobile.Droid.PushNotification
{
    [BroadcastReceiver(Permission = "com.google.android.c2dm.permission.SEND")]
    [IntentFilter(new string[] { "com.google.android.c2dm.intent.RECEIVE" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { "com.google.android.c2dm.intent.REGISTRATION" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { "com.google.android.gcm.intent.RETRY" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter (new[]{ Intent.ActionBootCompleted }, Categories = new[]{ Intent.CategoryDefault })]
    public class GCMBroadcastReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            MyIntentService.RunIntentInService(context, intent);
            SetResult(Result.Ok, null, null);
        }
    }
}

c) Add Intent service to process the notification

using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Media;
using Android.OS;
using Android.Support.V4.App;
using Consumer.Mobile.Infra;
using Consumer.Mobile.Services.PushNotification;
using Java.Lang;
using XLabs.Ioc;
using TaskStackBuilder = Android.Support.V4.App.TaskStackBuilder;

namespace Consumer.Mobile.Droid.PushNotification
{
    [Service]
    public class MyIntentService : IntentService
    {
        private readonly ILogger _logger;
        private readonly IPushNotificationService _notificationService;
        private readonly IPushNotificationRegister _pushNotificationRegister;

        public MyIntentService()
        {
            _logger = Resolver.Resolve<ILogger>();
            _notificationService = Resolver.Resolve<IPushNotificationService>();
            _pushNotificationRegister = Resolver.Resolve<IPushNotificationRegister>();
        }

        static PowerManager.WakeLock _sWakeLock;
        static readonly object Lock = new object();


        public static void RunIntentInService(Context context, Intent intent)
        {
            lock (Lock)
            {
                if (_sWakeLock == null)
                {
                    // This is called from BroadcastReceiver, there is no init.
                    var pm = PowerManager.FromContext(context);
                    _sWakeLock = pm.NewWakeLock(
                    WakeLockFlags.Partial, "My WakeLock Tag");
                }
            }

            _sWakeLock.Acquire();
            intent.SetClass(context, typeof(MyIntentService));
            context.StartService(intent);
        }

        protected override void OnHandleIntent(Intent intent)
        {
            try
            {
                Context context = this.ApplicationContext;
                string action = intent.Action;

                if (action.Equals("com.google.android.c2dm.intent.REGISTRATION"))
                {
                    HandleRegistration(context, intent);
                }
                else if (action.Equals("com.google.android.c2dm.intent.RECEIVE"))
                {
                    HandleMessage(context, intent);
                }
            }
            finally
            {
                lock (Lock)
                {
                    //Sanity check for null as this is a public method
                    if (_sWakeLock != null)
                        _sWakeLock.Release();
                }
            }
        }

        private void HandleMessage(Context context, Intent intent)
        {

            Intent resultIntent = new Intent(this, typeof(MainActivity));


            TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);

            var c = Class.FromType(typeof(MainActivity));
            stackBuilder.AddParentStack(c);
            stackBuilder.AddNextIntent(resultIntent);

            string alert = intent.GetStringExtra("Alert");
            int number = intent.GetIntExtra("Badge", 0);

            var imageUrl = intent.GetStringExtra("ImageUrl");
            var title = intent.GetStringExtra("Title");

            Bitmap bitmap = GetBitmap(imageUrl);

            PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(0, (int)PendingIntentFlags.UpdateCurrent);

            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .SetAutoCancel(true) // dismiss the notification from the notification area when the user clicks on it
                .SetContentIntent(resultPendingIntent) // start up this activity when the user clicks the intent.
                .SetContentTitle(title) // Set the title
                .SetNumber(number) // Display the count in the Content Info
                .SetSmallIcon(Resource.Drawable.Icon) // This is the icon to display
                .SetLargeIcon(bitmap)
                .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
                .SetContentText(alert); // the message to display.

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

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

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

        private void HandleRegistration(Context context, Intent intent)
        {
            var token = intent.GetStringExtra("registration_id");
            _logger.Info(this.Class.SimpleName, "Received Token : " + token);

            if (_pushNotificationRegister.ShouldSendToken(token))
            {
                var uid = Android.Provider.Settings.Secure.GetString(MainActivity.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
                _notificationService.AddPushToken(token, DeviceUtils.GetDeviceType(), uid);
            }
        }


        private Bitmap GetBitmap(string url)
        {

            try
            {
                System.Net.WebRequest request =
                    System.Net.WebRequest.Create(url);
                System.Net.WebResponse response = request.GetResponse();
                System.IO.Stream responseStream =
                    response.GetResponseStream();
                return BitmapFactory.DecodeStream(responseStream);


            }
            catch (System.Net.WebException)
            {
                return null;
            }

        }

    }
}

d) Implement the Interface IPushNotificationRegister: using Android.App; using Android.Content; using Consumer.Mobile.Services; using Consumer.Mobile.Services.PushNotification;

[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]

// Gives the app permission to register and receive messages.
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]

// Needed to keep the processor from sleeping when a message arrives
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
[assembly: UsesPermission(Name = "android.permission.RECEIVE_BOOT_COMPLETED")]
namespace Consumer.Mobile.Droid.PushNotification
{
    public class PushNotificationRegister : IPushNotificationRegister
    {          
        public override void ExtractTokenAndRegister()
        {
            string senders = AndroidConfig.GCMSenderId;
            Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER");
            intent.SetPackage("com.google.android.gsf");
            intent.PutExtra("app", PendingIntent.GetBroadcast(MainActivity.Context, 0, new Intent(), 0));
            intent.PutExtra("sender", senders);
            MainActivity.Context.StartService(intent);
        }


    }
}
Community
  • 1
  • 1
IdoT
  • 2,831
  • 1
  • 24
  • 35