Is it possible to simulate a GCM receive from the adb shell / am command line? I'm getting an error
Asked Answered
U

4

25

I'm trying to simulate as if the device is receiving a GCM push message by using adb and the command line. I've tried this command to broadcast a GCM intent:

adb shell am broadcast -c com.myapp -a com.google.android.c2dm.intent.RECEIVE -e data "SomeData"

This triggers a "Permission denial" log line though:

09-19 12:23:34.820      725-787/? W/BroadcastQueue﹕ Permission Denial: broadcasting Intent { act=com.google.android.c2dm.intent.RECEIVE cat=[com.myapp] flg=0x10 (has extras) } from null (pid=21244, uid=2000) requires com.google.android.c2dm.permission.SEND due to receiver com.myapp/com.google.android.gcm.GCMBroadcastReceiver

Relevant parts of my manifest:

<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<application>
<receiver
    android:name="com.google.android.gcm.GCMBroadcastReceiver"
    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" />
        <category android:name="com.myapp" />
    </intent-filter>
</receiver>
</application>

Any ideas?

Edit / clarification: Push / GCM receive works in production. I'm looking for an easier way to test changes.

Ushijima answered 19/9, 2014 at 10:33 Comment(1)
how do you add multiple key value or an intentInexertion
W
20

You need to remove the permission property in your receiver's definition like this:

<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<application>
<receiver
    android:name="com.google.android.gcm.GCMBroadcastReceiver" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="com.myapp" />
    </intent-filter>
</receiver>
</application>
Waldrup answered 5/10, 2014 at 12:18 Comment(1)
Works! I misunderstood that permission. Having that paramtere there, states we only want messages coming from activities having the SEND permission - which the command line tool doesn't have. Unsure if I want this in production though, but maybe I can tailor a manifest for Debug builds onlyUshijima
U
10

Better than temporarily editing AndroidManifest.xml to remove the permission check, and remembering to restore it later, you can automatically disable the permission check in debug builds.

To do this, set the attribute via a Manifest Merger placeholder:

<receiver
  android:name="com.google.android.gcm.GCMBroadcastReceiver"
  android:permission="${gcmPermissionRequired}">

then set the placeholder in build.gradle:

buildTypes {
    debug {
        ...
        manifestPlaceholders = [gcmPermissionRequired: ""] // "" => let the GCM BroadcastReceiver accept Intents from 'adb shell am broadcast'
    }
    release {
        ...
        manifestPlaceholders = [gcmPermissionRequired: "com.google.android.c2dm.permission.SEND"]
    }
}

(Note: Previously I used debug & release string resources. It turns out that the Play store rejects the app if it defines an intent filter permission using a string resource.)

Utile answered 3/4, 2015 at 3:8 Comment(2)
If the payload data is in JSON format, it's a difficult puzzle to quote that properly in the adb shell am broadcast command. See https://mcmap.net/q/539179/-sending-json-as-extra-data-in-an-android-broadcast-via-adb-gets-incorrectly-formatted for a solution.Utile
Since the Play store won't accept the string resource technique, I changed this to use a Manifest Merger placeholder.Utile
A
6

I suggest using command-line curl, as sending GCM pushes is as easy as calling some REST API. See sample shell script below:

#!/bin/bash

REGISTRATION_ID=YOUR_GCM_REGISTRATION_ID

SERVER_KEY=YOUR_SERVER_KEY_FROM_GOOGLE_API_CONSOLE

curl --header "Authorization: key=$SERVER_KEY" --header  Content-Type:"application/json"  https://android.googleapis.com/gcm/send  -d  "{ \"data\" : {\"foo\": \"bar\"}, \"registration_ids\":[\"$REGISTRATION_ID\"]  }"
Amatol answered 19/9, 2014 at 16:11 Comment(4)
GREAT tip! a small addition, you get the YOUR_GCM_REGISTRATION_ID in the application from "GoogleCloudMessaging.getInstance(context).register(...)"Harlene
I've decided to write few more words abot that, for both iOS and Android: codingfingers.com/testing-push-notifications-on-ios-and-androidAmatol
It's a good solution, but not optimal. What if you're offline? Or what if you want this to run as an integration test on a build server and don't want the server key stored there?Ushijima
I see your point, but I don't see better solution - however, you can try to add second receiver (maybe exposed just in some gradle build variant) & use it to deliver messages to GCMIntentService. Still - not perfect, but would just allow you to test how pushes are handled.Amatol
M
0
  1. Install adb first.

sudo apt-get install adb

  1. Remove the SEND permission from manifest.xml.

android:permission="com.google.android.c2dm.permission.SEND" >

  1. Command to push notifications from shell

adb shell am broadcast -c com.myapp -a com.google.android.c2dm.intent.RECEIVE -e data "SomeData"

  1. Change the package name (com.myapp) and "SomeData" as you want.
Melisa answered 20/3, 2018 at 6:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.