2
votes

I have been trying for several hours to enable push notification for Android so I can use it with Amazon SNS. Have tried to follow the code as described in the documentation: http://docs.aws.amazon.com/mobile/sdkforxamarin/developerguide/getting-started-sns-android.html

Seems like I am doing something wrong because the "intent" I create has "action" set to null which cause an exception in OnHandleIntent. Has anyone experience with that? I am pretty new to Android so my understanding of "intents", .. is rather limited.

Here is the MainActivity

[Activity (Label = "awst", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity
{
int count = 1;

    protected override void OnCreate (Bundle savedInstanceState)
    {
        base.OnCreate (savedInstanceState);

        // Set our view from the "main" layout resource
        SetContentView (Resource.Layout.Main);

        // Get our button from the layout resource,
        // and attach an event to it
        Button button = FindViewById<Button> (Resource.Id.myButton);

        button.Click += delegate {

            button.Text = string.Format ("{0} clicks!", count++);

            var intent = new Intent (this, typeof (GCMIntentService));      


        };

    }
}

[BroadcastReceiver(Permission = "com.google.android.c2dm.permission.SEND")]
[IntentFilter(new string[] {
    "com.google.android.c2dm.intent.RECEIVE"
}, Categories = new string[] {
    "com.companyname.awst" /* change to match your package */
})]
[IntentFilter(new string[] {
    "com.google.android.c2dm.intent.REGISTRATION"
}, Categories = new string[] {
    "com.companyname.awst" /* change to match your package */
})]
[IntentFilter(new string[] {
    "com.google.android.gcm.intent.RETRY"
}, Categories = new string[] {
    "com.companyname.awst" /* change to match your package */
})]

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

        GCMIntentService.RunIntentInService(context, intent);
        SetResult(Result.Ok, null, null);
    }
}

[BroadcastReceiver]
[IntentFilter(new[] {
    Android.Content.Intent.ActionBootCompleted
})]

public class GCMBootReceiver: BroadcastReceiver {
    public override void OnReceive(Context context, Intent intent) {
        GCMIntentService.RunIntentInService(context, intent);
        SetResult(Result.Ok, null, null);
    }
}
}

and the Intent service

namespace awst.Droid
{
[Service]
public class GCMIntentService: 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(GCMIntentService));

        // 
        context.StartService(intent); 
    }

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

            // !!!!!!
            // this is where the code fails with action beeing null
            // !!!!!!

            if (action.Equals("com.google.android.c2dm.intent.REGISTRATION")) {
                HandleRegistration(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(Intent intent) {

        Globals config = Globals.Instance;

        string registrationId = intent.GetStringExtra("registration_id");
        string error = intent.GetStringExtra("error");
        string unregistration = intent.GetStringExtra("unregistered");

        if (string.IsNullOrEmpty(error)) {

            config.snsClient.CreatePlatformEndpointAsync(new CreatePlatformEndpointRequest {
                Token = registrationId,
                PlatformApplicationArn = config.AWS_PlaformARN /* insert your platform application ARN here */
            });
        }
    }

    private void HandleMessage(Intent intent) {
        string message = string.Empty;
        Bundle extras = intent.Extras;
        if (!string.IsNullOrEmpty(extras.GetString("message"))) {
            message = extras.GetString("message");
        } else {
            message = extras.GetString("default");
        }

        Log.Info("Messages", "message received = " + message);

        ShowNotification("SNS Push", message);
        //show the message

    }

    public void ShowNotification(string contentTitle,
        string contentText) {
        // Intent
        Notification.Builder builder = new Notification.Builder(this)
            .SetContentTitle(contentTitle)
            .SetContentText(contentText)
            .SetDefaults(NotificationDefaults.Sound | NotificationDefaults.Vibrate)
            //todo
            .SetSmallIcon(Resource.Mipmap.Icon)
            .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification));

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

        notificationManager.Notify(1001, builder.Build());
    }
}
}

So questions:

How do I register the device so I can then send a push from SNS? Is there a different way I should consider??? Are there any other steps I must take for this to work? I did upload the certificate to AWS but do I need to configure any permissions in the app code??

Thanks a lot!!!

Chris

1

1 Answers

4
votes

You may want look at the SNS sample in GitHub or via the Xamarin component store to augment the getting started, you may find some things that you are missing and are not fully covered in the getting started guide. Something that calls out to me that is present in the example but not in your code is RegisterForGCM() in the main activity:

private void RegisterForGCM()
{
    string senders = Constants.GoogleConsoleProjectId;
    Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER");
    intent.SetPackage("com.google.android.gsf");
    intent.PutExtra("app", PendingIntent.GetBroadcast(this, 0, new Intent(), 0));
    intent.PutExtra("sender", senders);
    StartService(intent);
}