0

I implemented the app engine module with Google Cloud Messaging, the devices are registrated succesfully and I deployed it live already. My question is, by doing a RESTful API with this integration, do I need to make a server side code, for sending push notifications, or can I send them through the client-side part?

Here´s my Android Manifest code:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="myPackage">
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />
    <uses-feature
        android:name="android.hardware.Camera2"
        android:required="true" />
    <!-- This filters devices that don't support sip -->
    <uses-feature
        android:name="android.hardware.sip.voip"
        android:required="true" />
    <uses-feature
        android:name="android.hardware.wifi"
        android:required="true" />
    <uses-feature
        android:name="android.hardware.microphone"
        android:required="true" />
    <receiver
        android:name=".IncomingCallReceiver"
        android:label="Call Receiver" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- [START gcm_permission] -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" >
    <!-- [END gcm_permission] -->
    <permission
        android:name="myPackage.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="myPackage.permission.C2D_MESSAGE" />
    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name="com.facebook.FacebookActivity"
            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
        <activity android:name=".LogInActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_app_id" />
        <meta-data
            android:name="com.facebook.sdk.ApplicationId"
            android:value="@string/facebook_app_id" />

        <activity android:name=".MainActivity" />
        <activity
            android:name=".Messaging.Activities.FriendsRequestsActivity"
            android:parentActivityName=".MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".MainActivity" />
        </activity>
        <activity
            android:name=".Messaging.Activities.ChatActivity"
            android:launchMode="singleTop"
            android:parentActivityName=".MainActivity"
            android:screenOrientation="portrait"
            android:theme="@style/ChatTheme"
            android:windowSoftInputMode="adjustResize|stateHidden">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".MainActivity" />
        </activity>

        <receiver
            android:name="com.google.android.gms.gcm.GcmReceiver"
            android:exported="true"
            android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="myPackage" />
            </intent-filter>
        </receiver>

        <service
            android:name=".Utils.InstanceIDListener"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.gms.iid.InstanceID" />
            </intent-filter>
        </service>

        <service
            android:name="myPackage.Utils.RegistrationIntent"
            android:exported="false"></service>

        <service
            android:name="myPackage.Utils.GcmListener"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>
    </application>

</manifest>`

This is my GcmListener that receives that is supposed to be receiving the message:

public class GcmListener extends GcmListenerService {

    private static final String TAG = "Push";

    /**
     * Called when message is received.
     *
     * @param from SenderID of the sender.
     * @param data Data bundle containing message data as key/value pairs.
     *             For Set of keys use data.keySet().
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(String from, Bundle data) {
        JSONObject jsonObject = new JSONObject();
        Log.d(TAG, "Push received");
        Set<String> keys = data.keySet();
        for (String key : keys) {
            try {
                jsonObject.put(key, data.get(key));
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        try {
            sendNotification("Received: " + jsonObject.toString(5));//TODO Forward to be written
        } catch (JSONException e) {
            e.printStackTrace();
        }

        if (from.startsWith("/topics/")) {
            // message received from some topic.
        } else {
            // normal downstream message.
        }

        // [START_EXCLUDE]
        /**
         * Production applications would usually process the message here.
         * Eg: - Syncing with server.
         *     - Store message in local database.
         *     - Update UI.
         */

        /**
         * In some cases it may be useful to show a notification indicating to the user
         * that a message was received.
         */
        //sendNotification(message); TODO create the correct notification to be showed to the user
        // [END_EXCLUDE]
    }
}

The sendNotification method is not written yet, but I put a log to check if the message was received, and I get nothing,I honestly think I used the wrong API_KEY from the Google Developers Console, I am using the: Server key (auto created by Google Service), or maybe the order of the declarations of the services in the manifest. Those are the only things that I can think of that could be causing the app not to get the push message

Johanna
  • 5
  • 1
  • 5
  • you can use this tutorial (the answer was accepted) to check your API_KEY or registration ids is wrong or not.. after that please let me know: http://stackoverflow.com/questions/22168819/android-test-push-notification-online-google-cloud-messaging – Bui Quang Huy Mar 22 '16 at 04:06
  • I get this message: Unauthorized Error 401 – Johanna Mar 22 '16 at 04:28
  • When I change the Server API_KEY to the Android API_KEY I get this: {"multicast_id":4751777491966629353,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MismatchSenderId"}]} – Johanna Mar 22 '16 at 04:31
  • It mean your project id is wrong. you can go to google project site and check again – Bui Quang Huy Mar 22 '16 at 04:52
  • I made it yeah the wrong this was I was using the proyect ID instead of the proyect number...Thanks a lot!!!!!!!!!!!!!!!!!!!!!!!!! you are great!! – Johanna Mar 22 '16 at 05:33
  • by any change you know something about Google Cloud Storage, this is the specific question = http://stackoverflow.com/questions/36238241/google-cloud-storage – Johanna Mar 26 '16 at 17:11
  • sorry but I dont have any experience at Google Cloud Storage :D – Bui Quang Huy Mar 27 '16 at 06:05
  • thats ok, million thanks anyway!!! :D – Johanna Mar 27 '16 at 19:47

1 Answers1

2

No need to build your own server if you just want to send message between two client device. Just send send your message with opponent's registration id and they will receive it. Anyway, if you want to store that message, you should build one.

You can create an object like this, put registration_ids and data you want to send in it

public class MessageSenderContent implements Serializable {
    private List<String> registration_ids;
    private Map<String, String> data;

    public void addRegId(String regId){
        if (registration_ids==null){
            registration_ids = new LinkedList<String>();
            registration_ids.add(regId);
        }
    }

    public void createData(String title,String message) {
        if (data == null)
            data = new HashMap<String, String>();

        data.put("title", title);
        data.put("message", message);
    }

    public Map<String, String> getData() {
        return data;
    }

    public void setData(Map<String, String> data) {
        this.data = data;
    }

    public List<String> getRegIds() {
        return registration_ids;
    }

    public void setRegIds(List<String> regIds) {
        this.registration_ids = regIds;
    }

    @Override
    public String toString() {
        return "MessageSenderContent{" +
                "registration_ids=" + registration_ids +
                ", data=" + data +
                '}';
    }

}

UPDATE 1 You need to put data to that object like this and make a http request to the server:

 private static MessageSenderContent createMegContent(String regId, String title) {
        String message = txt_chat.getText().toString();
        MessageSenderContent mgsContent = new MessageSenderContent();
        mgsContent.addRegId(regId);// add registration_id of the device you want to send
        mgsContent.createData(title, message);
        return mgsContent;
    }

UPDATE 2

This is my class that will send http request to the server:

public class MessageSender {

    private int responseCode;

    public boolean sendPost(MessageSenderContent content) {

        HttpURLConnection connection;
        try {
            URL gcmAPI = new URL("https://android.googleapis.com/gcm/send");
            connection = (HttpURLConnection) gcmAPI.openConnection();

            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type","application/json");
            connection.setRequestProperty("Authorization", "key=" + AppConfig.API_KEY); //api_key is what generate when you register a project  in google console
            connection.setDoOutput(true);
            ObjectMapper mapper = new ObjectMapper();         mapper.setVisibility(PropertyAccessor.FIELD,JsonAutoDetect.Visibility.ANY);
            DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());

            mapper.writeValue(dataOutputStream, content);

            dataOutputStream.flush();
            dataOutputStream.close();

            responseCode = connection.getResponseCode();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (responseCode == 200) {
            Log.i("Request Status", "This is success response status from server: " + responseCode);
            return true;
        } else {
            Log.i("Request Status", "This is failure response status from server: " + responseCode);
            return false;
        }
    }
}

In my activity I will create an instance of it and use it to send MessageSenderContent to GCM server like this:

                    MessageSender mgsSender = new MessageSender();
                    new AsyncTask<Void, Void, Void>() {
                        @Override
                        protected Void doInBackground(Void... params) {
                            MessageSenderContent mgsContent = createMegContent(registration_Id, your_title);

                            mgsSender.sendPost(mgsContent)
                            return null;
                        }
                    }.execute();

Service manifest code:

        <service
            android:name="training.com.services.MessageListenerService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </service>
Khoa Tran
  • 471
  • 6
  • 16
Bui Quang Huy
  • 1,636
  • 2
  • 13
  • 44
  • and sorry for the ignorance, but how can I connect this message object with the Google Cloud Messaging for it to be send? – Johanna Mar 18 '16 at 03:40
  • Hi there I think Im very close on understanding your answer, I´m just not that clear why the createMegContent returns a MessageSenderContent, and how can I make GCM send that respective message with the gotten token – Johanna Mar 18 '16 at 04:39
  • wow, greate answer!!!!!! just two more quick questions, what are the AppConfig.GCM_API and the AppConfig.APi_KEY, I suppose the last one is the API Key of the general app, the one I have to put in the manifest – Johanna Mar 18 '16 at 05:21
  • That some global variable I save to use in everywhere of my app :) GCM_API is just : https://android.googleapis.com/gcm/send and API_KEY is which generate when you register application at google – Bui Quang Huy Mar 18 '16 at 05:50
  • just update the answer again, you can take a look in two variable – Bui Quang Huy Mar 18 '16 at 05:54
  • Hi sorry for the insistence, I can get the token, send the token to GCM and I get the requestCode 200 that indicates that the request code was succesfully sent, but I still can´t get the push, I hace check the Manifest and all seems to be correct, what could be happening? – Johanna Mar 21 '16 at 04:12
  • @Johanna Maybe it due to your BroadcastReceiver is wrong. Have you defined it in the Manifest yet? – Bui Quang Huy Mar 21 '16 at 06:22
  • or you can try to close and open your emulator again, many I got message delay and solve by this way (maybe just in my case) – Bui Quang Huy Mar 21 '16 at 06:27
  • this is the declaration of the receiving part of the message : ` ` – Johanna Mar 21 '16 at 14:36
  • could you update full of your Manifest file in your question? – Bui Quang Huy Mar 21 '16 at 16:50
  • Did you use class extends GcmListenerService and override onMessageReceived().. method? I update my manifest code of service above. – Bui Quang Huy Mar 22 '16 at 01:25