0

I'm able to receive a GCM registration id (for push notifications) thanks to this google guide and store the reg.id in a database and without authentication everything works fine. I use web api 2, oauth 2 authentication and account manager.

1) User sign in to application, App creates an account for the user.
- Or if an account exists auto sign the user in.
2) App gets auth token, if expired retrieves it via Volley string request
3) App checks UserData of Account Manager if reg. id received before. If not App requests an reg. id from GCM and posts it to the server via Volley(AuthToken is required here) and App sets a userdata in account that reg. id has received.

With the above flow of my app which is exists only in my mind at the moment, I've some questions.

First, how can I get auth token first and move to the step 3 which is IntentService according to the Guide.

Second, let's say we managed to do first question. What happens if user login to his account from a different device? Should I update his reg. id for his new device. But what if this device was temporary and he returns to use his permanent device? Notifications will be sent to tempopary device because it was the last device he signed in!

I'm really confused and will be apreciated for anyone who lights my way. Thanks.

Edit

Instead of following Google's guide (instead of using IntentService) is it possible getting both Authorization Token and Registration Id(Token) in a AsyncTask?

cck
  • 174
  • 1
  • 11
  • I suggest you read through the documentation first https://developers.google.com/cloud-messaging/android/client – tyczj Aug 24 '15 at 12:58
  • This is the link to my google guide and I've already read it(again). I learn Device Group Messaging thanks to @Mateusz Pryczkowski. But what about auth token? Did I miss sth? – cck Aug 24 '15 at 13:15
  • you get the token by getting the InstanceID and calling `instanceID.getToken` – tyczj Aug 24 '15 at 13:17
  • Yes, that gives me a Registration Token but I also need Authorization Token for my volley request which is only obtained by an async request. Both running an IntentService and an AsyncTask is not possible. – cck Aug 24 '15 at 13:24
  • 1
    There is no requirement that you use an IntentService to call InstanceID.getToken. So yes you can get your auth token and instance id token in an AsyncTask. – Arthur Thompson Aug 24 '15 at 18:23

2 Answers2

1

Just as answer for 2nd part of question. Relation between user and his regId should be 1 to n. So 1 user can have multiple devices, and by this multiple regId. And when you would like to send message to this user - you should send multiple messages (1 to every device). Other possible solution is using lately introduced Device Group Messaging, and IMO is preferable way for it.

Mateusz Pryczkowski
  • 1,874
  • 1
  • 16
  • 20
0

Thanks for your answers, it only works if I use two async tasks and here is my solution. Any criticism or recommendation will be welcome.

I create a TokenCheckerActivity and put it between login activity and main activity.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_token_checker);

    webApiUri = "url Here";
    tokenContext = this;

    accountManager = accountManager.get(tokenContext);
    PpSharedPreferences ppSharedPreferences = new PpSharedPreferences(tokenContext);
    ppAuthenticator = new PpAuthenticator(tokenContext);

    account = ppAuthenticator.getCurrentAccount(ppSharedPreferences.getUsername());

    new GetAuthorizationToken().execute(ppSharedPreferences.getUsername());
}

Async Tasks

/**
 * Gets the authorization token and checks if GCM registration id received.
 * Gets reg is if not exists.
 */
private class GetAuthorizationToken extends AsyncTask<String,Void,String>{
    @Override
    protected String doInBackground(String... params) {
        String username = params[0];
        String mAuthToken = ppAuthenticator.getPpAuthToken(username);
        return mAuthToken;
    }

    @Override
    protected void onPostExecute(String authToken) {
        if(!TextUtils.isEmpty(authToken))
        {
            final String gcmTokenSent = accountManager.getUserData(account, AccountGeneral.GCM_REGISTRATION_ID);
            if (gcmTokenSent == null || !gcmTokenSent.equals("true")) {
                new GetGcmRegistrationToken().execute(authToken);
            } else {
                // We have the Gcm Registration Id continue to the main activity
                Intent intent = new Intent(tokenContext, MainActivity.class);
                startActivity(intent);
                finish();
            }
        }
    }
}


private class GetGcmRegistrationToken extends AsyncTask<String,Void,PpTokens>{
    @Override
    protected PpTokens doInBackground(String... params) {
        PpTokens tokens = new PpTokens();
        tokens.setAuthToken(params[0]);
        try {
            if (checkPlayServices()) {
                InstanceID instanceID = InstanceID.getInstance(tokenContext);
                String regToken = instanceID.getToken(getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
                tokens.setRegToken(regToken);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return tokens;
    }

    @Override
    protected void onPostExecute(PpTokens tokens) {
        if (!TextUtils.isEmpty(tokens.getRegToken()))
        {
            sendRegistrationToServer(tokens.getRegToken(),tokens.getAuthToken());
        }
    }
}

    private class PpTokens
{
    private String authToken;
    private String regToken;

    public String getAuthToken() {
        return authToken;
    }

    public void setAuthToken(String authToken) {
        this.authToken = authToken;
    }

    public String getRegToken() {
        return regToken;
    }

    public void setRegToken(String regToken) {
        this.regToken = regToken;
    }
}

Send reg id to server

private void sendRegistrationToServer(String regToken, final String authToken) {
    final String tag_json_obj = "json_obj_req";
    String url = webApiUri + "?gcmRegistrationToken=" + regToken;

    JsonObjectRequest objectRequest = new JsonObjectRequest(Request.Method.POST, url, new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {

            try {
                Log.d("Name for Reg Token:", response.getString("Name"));

                // You should store a boolean that indicates whether the generated token has been
                // sent to your server. If the boolean is false, send the token to your server,
                // otherwise your server should have already received the token.
                accountManager.setUserData(account, AccountGeneral.GCM_REGISTRATION_ID, "true");

                Intent intent = new Intent(tokenContext, MainActivity.class);
                startActivity(intent);
                finish();

            } catch (JSONException e) {
                e.printStackTrace();
            }

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            String errorMessage = JsonErrorMessageHandler.onErrorResponse(error);
            accountManager.setUserData(acc, AccountGeneral.GCM_REGISTRATION_ID, "false");
        }
    }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("Authorization", "Bearer " + authToken);
            return headers;
        }
    };

    int socketTimeout = 5000;
    int maxRetries = 3;
    RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, maxRetries, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
    objectRequest.setRetryPolicy(policy);

    // Adding request to request queue
    AppController.getInstance().addToRequestQueue(objectRequest, tag_json_obj);
}
cck
  • 174
  • 1
  • 11