1

I'm creating android app which is using GCM with Xamarin. I followed this guide from Xamarin team and then this guide from Google team

After I implemented Xamarin version of Gcm I received nothing at my BroadcaseReceiver.OnReceive at all. Here is Manifest and BroadcastReceiver

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
          android:installLocation="auto" 
          package="com.pushtest.droid" 
          android:versionCode="1" 
          android:versionName="1">

  <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" />

  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
  <uses-permission android:name="android.permission.GET_ACCOUNTS" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />

  <permission android:name="com.pushtest.droid.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
  <uses-permission android:name="com.pushtest.droid.permission.C2D_MESSAGE" />

  <application android:label="push droid"/>
</manifest>

BroadcastReceiver:

[BroadcastReceiver(Permission = "com.google.android.c2dm.permission.SEND")]
    [IntentFilter(new[] {"com.google.android.c2dm.intent.RECEIVE"}, Categories = new[] {"com.pushtest.droid"})]
    [IntentFilter(new[] {"com.google.android.c2dm.intent.REGISTRATION"}, Categories = new[] {"com.pushtest.droid"})]
    [IntentFilter(new[] {"com.google.android.gcm.intent.RETRY"}, Categories = new[] {"com.pushtest.droid"})]
    public class MyGcmBroadcastReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            System.Diagnostics.Debug.WriteLine("MyGcmBroadcastReceiver.OnReceive");
            if (intent.Action == "com.google.android.c2dm.intent.REGISTRATION")
            {
                var registrationId = intent.GetStringExtra("registration_id");
                var error = intent.GetStringExtra("error");
                var unregistered = intent.GetStringExtra("unregistered");
                System.Diagnostics.Debug.WriteLine("!!!! Registration status |R: {0}|E: {1}|U: {2}", registrationId, error, unregistered);
            }
            else if (intent.Action == "com.google.android.c2dm.intent.RECEIVE")
            {
                System.Diagnostics.Debug.WriteLine("!!!! Push Received: |TBD|");
            }
        }
    }

When I started intent I got just nothing - no errors, no debug info, no result:

private void RegisterForGcm(Context context)
        {
            const string SenderId = "PROJECT_ID_FROM_GOOGLE_CONSOLE";
            var appExtra = PendingIntent.GetBroadcast(context, 0, new Intent(), 0);

            var intent = new Intent("com.google.android.c2dm.intent.REGISTER");
            intent.PutExtra("app", appExtra);
            intent.PutExtra("sender", SenderId);
            context.StartService(intent);
        }

Then I went thought Google's guide at finally got registration response with error = "SERVICE_NOT_AVAILABLE":

No extra strings were there (no registraion_id). Debug info: !!!! Registration status |R: |E: SERVICE_NOT_AVAILABLE|U:

Here is my Manifest and BroadcastReceiver (intent start is the same):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
          android:installLocation="auto" 
          package="com.pushtest.droid" 
          android:versionCode="1" 
          android:versionName="1">

  <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" />

  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
  <uses-permission android:name="android.permission.GET_ACCOUNTS" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />

  <permission android:name="com.pushtest.droid.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
  <uses-permission android:name="com.pushtest.droid.permission.C2D_MESSAGE" />

  <application android:label="push droid">
    <receiver android:name="com.pushtest.droid.MyGcmBroadcastReceiver"
              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" />
        <action android:name="com.google.android.gcm.intent.RETRY" />

        <category android:name="com.pushtest.droid" />
      </intent-filter>
    </receiver>
  </application>
</manifest>

and BroadcastReceiver (without any attributes)

 public class MyGcmBroadcastReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            System.Diagnostics.Debug.WriteLine("MyGcmBroadcastReceiver.OnReceive");
            if (intent.Action == "com.google.android.c2dm.intent.REGISTRATION")
            {
                var registrationId = intent.GetStringExtra("registration_id");
                var error = intent.GetStringExtra("error");
                var unregistered = intent.GetStringExtra("unregistered");
                System.Diagnostics.Debug.WriteLine("!!!! Registration status |R: {0}|E: {1}|U: {2}", registrationId, error, unregistered);
            }
            else if (intent.Action == "com.google.android.c2dm.intent.RECEIVE")
            {
                System.Diagnostics.Debug.WriteLine("!!!! Push Received: |TBD|");
            }
        }
    }

Test Example here: https://dl.dropboxusercontent.com/u/19503836/pushtest-issue.zip

I was trying this code on my Android 2.3.6 Device Any help is very appreciated.

TIA!

Mando
  • 11,414
  • 17
  • 86
  • 167
  • Do you have a google account on the phone? – TombMedia Oct 16 '13 at 06:55
  • Yes I have, I can access Google Play Store using this configured account – Mando Oct 16 '13 at 15:00
  • And as well you have this application registered with GCM for API access? Can you post code to your intentservice as well? – TombMedia Oct 16 '13 at 18:04
  • Yes, I registered my project at google console and allow it to use GCM. Just edited the post and added source code – Mando Oct 16 '13 at 18:48
  • http://stackoverflow.com/questions/17188982/how-to-fix-google-cloud-messaging-registration-error-service-not-available is a closely related question (if not a duplicate). – Brian Marick Jan 21 '15 at 14:04

2 Answers2

1

You have not created Service [IntentService ] Class. Starting Service but have not created that.BroadCastReceiver will look like below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace hellomultiscreen
{

    public class MyGCMBroadcastReceiver : BroadcastReceiver
    {

        const string TAG = "PushHandlerBroadcastReceiver";
        public override void OnReceive(Context context, Intent intent)
        {

            MyIntentService.RunIntentInService(context, intent);
            SetResult(Result.Ok, null, null);
            Toast.MakeText(context, "Received Message!", ToastLength.Short).Show();
        }
    }
}

and Intent Service will look like below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V4.App;
using Android.Preferences;
using String = System.String;
namespace hellomultiscreen
{

    [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(intent);
                }
            }
            finally
            {
                lock (LOCK)
                {
                    //Sanity check for null as this is a public method
                    if (sWakeLock != null)
                        sWakeLock.Release();
                }
            }
        }
        private void HandleRegistration(Context context, Intent intent)
        {
            String registration = intent.GetStringExtra("registration_id");
            if (intent.GetStringExtra("error") != null)
            {
                // Registration failed, should try again later.
            }
            else if (intent.GetStringExtra("unregistered") != null)
            {
                // unregistration done, new messages from the authorized sender will be rejected
            }
            else if (registration != null)
            {

                string score = "Successful Login To Bullseye Account";
                long[] vibraPattern = { 0, 500, 250, 500 };

                Bundle valuesForActivity = new Bundle();
                valuesForActivity.PutString("score", score);

                // Create the PendingIntent with the back stack             
                // When the user clicks the notification, SecondActivity will start up.
                Intent resultIntent = new Intent(this, typeof(NotificationDetails));
                resultIntent.PutExtras(valuesForActivity); // Pass some values to SecondActivity.

                TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);
                stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(NotificationDetails)));
                stackBuilder.AddNextIntent(resultIntent);

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

                // Build the notification
                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(score) // Set the title
                    .SetNumber(1) // Display the count in the Content Info
                    .SetSmallIcon(Resource.Drawable.alert) // This is the icon to display
                    .SetVibrate(vibraPattern)

                    .SetContentText(score); // the message to display.

                // Finally publish the notification
                NotificationManager notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
                notificationManager.Notify(1, builder.Build());

            }
        }
        private void HandleMessage(Intent intent)
        {
            try
            {
                string score = intent.GetStringExtra("message");
                long[] vibraPattern = { 0, 500, 250, 500 };

                Bundle valuesForActivity = new Bundle();
                valuesForActivity.PutString("score", score);

                // Create the PendingIntent with the back stack             
                // When the user clicks the notification, SecondActivity will start up.
                Intent resultIntent = new Intent(this, typeof(NotificationDetails));
                resultIntent.PutExtras(valuesForActivity); // Pass some values to SecondActivity.

                TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);
                stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(NotificationDetails)));
                stackBuilder.AddNextIntent(resultIntent);

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

                // Build the notification
                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(score) // Set the title
                    .SetNumber(1) // Display the count in the Content Info
                    .SetSmallIcon(Resource.Drawable.alert) // This is the icon to display
                    .SetContentText(score); // the message to display.

                // Finally publish the notification
                NotificationManager notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
                notificationManager.Notify(1, builder.Build());

                //
            }
            catch 
            {

            }
        }
    }
}
0

I've never bothered trying to build our own push tech because PushSharp works so well. He has monodroid and monotouch examples with working code. We've always used that at work and other than a couple of old bugs that have been fixed the library has been solid.

I've looked at the manifest my apps generate and its got some things in it that yours does not. If you insist on building your own service at least take a look at his code and see how he's doing it.

Link to GitHub project

TombMedia
  • 1,962
  • 2
  • 22
  • 27