Adding Google Cloud Messagin (GCM) for Android - Registration process - android

I have been struggling with GCM implementation for some weeks now, but how I really want to get to understand how it works I decided to take 'baby steps'.
First of all, as mentioned here, I understood that the first thing to do is register my device/app must first register with GCM.
To verify that they can send and receive messages, client apps must register with GCM. In this process, the client obtains a unique registration token.
I'd like to know if the procedure and code below represent the very minimal code necessary to make such registration (the 'very minimal code necessary' is because when I learned OpenGL ES 2.0 and started to deal with shaders, I saw that when dealing with hard/confusing concepts, If you understand the minimal code necessary you can later understand what the "peripheral" code)
Procedure to registrate the app with GCM:
Create a project at Google Developer Console;
Activate "Cloud Messaging for Android" API;
Create a server API key at "Credentials";
Take note of the project ID;
Take note of the project number;
Take note of the server API key;
Create a Android Studio project;
Add an "App Engine Backend with CGM" module type;
On the "appengine-web.xml" window that will open, type in the application ID and the server API Key.
Create a main activity, using the project number (SENDER_ID).
After I didn all of that and run the app, I got a token with 152 characters.
Is all of that correct? Considering that I got a token back, is my device registered with GCM?
appengine-web.xml:
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>mygcmtest...</application>
<version>1</version>
<threadsafe>true</threadsafe>
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
<property name="gcm.api.key" value="AIza..." />
</system-properties>
</appengine-web-app>
MainActivity:
public class MainActivity extends AppCompatActivity {
private final Context mContext = this;
private final String SENDER_ID = "319899...";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getGCMToken();
}
private void getGCMToken() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
InstanceID instanceID = InstanceID.getInstance(mContext);
String token = instanceID.getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
Log.e("GCM Token", token);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.aninha.mygcmtest..." >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="com.example.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

Is my answer with source code at your question How to implement a GCM Hello World for Android using Android Studio is not enough for you to create two simple GCM projects (server-side and client-side) yet? :)
Of course, the sample code I used is just for a very basic case "server app sends, client app receives and displays message".
To sum up, you need to do the following steps:
Create a new project at Google Developers Console . At this
step, for simplicity, you just need to take note of 2 values: Project Number, which
will be used as SENDER_ID in my client project; and API server key (created at Credentials), which
will be used as API_KEY in my server project.
Create a new simple Android project for server side (with basic source code as my answer in your previous question).
Create a new simple Android project for client side (with basic source code as my answer in your previous question, I customized from the original source at Google Cloud Messaging - GitHub).
Run the client app, you will get the registration token (means that your device has successfully registered). Then, paste (hard-code) this token at CLIENT_REGISTRATION_TOKEN variable in server app.
Run the server app, and check the result (client app received the message or not)
Hope this helps!
P/S: I don't use any appengine-web.xml file

Related

Branch.io and Instant Apps

I have an app that's using Branch.io and am in process of updating it to support Instant Apps. Part of this change will require using app links to navigate from one part of app to another.
The Activity that I'm opening is configured to use Branch.io (e.g. using instructions in https://dev.branch.io/marketing-channels/android-instant-apps/guide/) and includes following in it's onStart() method. However I'm not seeing parameters I'm including in deep link in referringParams.
Branch.getInstance().initSession(new Branch.BranchReferralInitListener() {
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
Log.d("Branch", "onInitFinished() with deep link data: " + referringParams);
}
});
Do I need to trigger opening of the branch link in particular way from Android code for this to work?
BTW referringParams above does show +clicked_branch_link being false.
UPDATE
Just to clarify a few things. I'm trying for example to launch ActivityB from ActivityA using app deep link. ActivityB includes <intent-filter> as described in https://dev.branch.io/marketing-channels/android-instant-apps/guide/ for example. In ActivityA I'm currently trying to open/create Branch.io link as follows (have also formed link directly, as is used in that android-instant-apps sample for example, but that's not considered a "branch link")
HashMap<String, String> metadata = new HashMap<>();
metadata.put(PARAM, param);
BranchUniversalObject branchUniversalObject = new BranchUniversalObject().addContentMetadata(metadata);
LinkProperties linkProperties = new LinkProperties();
branchUniversalObject.generateShortUrl(context, linkProperties, (url, error) -> {
if (error == null) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
context.startActivity(intent);
}
});
If I try to open the url generated (by generateShortUrl) directly on device (clicking on link for example) then ActivityB is launched and I see the param I included in initSession callback. If I try to open it using code above (navigating betweeen ActivityA and ActivityB then ActivityB is launched but don't get the params (and +clicked_branch_link is false)
Sojan from Branch here
If you are trying to deep link to a new feature from another instant app apk unfortunetely Branch is not supporting this feature now.
If you are trying to get deep link params on opening an activity B in a new feature from activity A from another feature in an installed app you can achieve it in the following way.
ActivityA.java
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("yourBranchLink"));
intent.putExtra("branch","yourBranchLink");
intent.putExtra("branch_force_new_session",true);
Hope this helps
In order to configure the Branch SDK with your Instant App supported Android App you can follow the steps below:
1. Initialize the Branch SDK
Initialize the Branch SDK in the onCreate() method of your Application class. If you plan on deep linking from your Android Instant App to your full Android app after its installed, you'll need to add the line enablePlayStoreReferrer. This adds a delay to the initialization to wait for the Google Play Referrer, which can take up to a second.
public void onCreate() {
super.onCreate();
// This is needed to deferred deep link from an Android Instant App to a full app
// It tells the Branch initialization to wait for the Google Play Referrer before proceeding.
Branch.enablePlayStoreReferrer(1000L);
// Initialize the Branch SDK
Branch.getAutoInstance(this);
}
2. Add your Branch keys and register for Install Referrer
Instant Apps can be rather confusing as there are many different manifests, but you want to find the Manifest that contains your application tags. Make sure your Application class name is defined here, and then specify the Branch keys inside the application element.
<application
android:allowBackup="true"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:supportsRtl="true"
android:name=".MyApplication">
<!-- Set to true to use Branch_Test_Key -->
<meta-data android:name="io.branch.sdk.TestMode" android:value="false" />
<meta-data android:name="io.branch.sdk.BranchKey" android:value="key_live_app_live_key" />
<meta-data android:name="io.branch.sdk.BranchKey.test" android:value="key_test_app_test_key" />
<receiver android:name="io.branch.referral.InstallListener" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
</application>
3. Configure your Branch links as Android App Links
Assuming you've already configured Branch for Android App Links for your Android App the next step is to add the intent filter for App links support in your Application Tag. Make sure to replace the xxxx with your link Domain. (If you haven't configured your full native app to use Branch as Android App Links you can follow the steps mentioned here and here.)
<application
......
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="xxxx.app.link" />
<data android:scheme="https" android:host="xxxx-alternate.app.link" />
</intent-filter>
</application>
4. Retrieve Branch deep link data
Add Branch initSession in Activities which are configured to open from a link click in order to receive the deep link params. This will return the deep link data from the referring link.
protected void onStart() {
super.onStart();
Branch.getInstance().initSession(new Branch.BranchReferralInitListener() {
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
Log.d("Branch","onInitFinished() with deep link data: " + referringParams);
}
});
}
5. Configure the deep linking from Instant App to your Full App
To convert your user who just arrived in your Instant App to your full native app, Branch SDK provides convenient methods to check for app types and full app conversion. This eliminates the dependency on Google IA support SDK ('com.google.android.instantapp'). Here are some of the methods:
Branch.isInstantApp()
This convenience method checks whether the current version of app running is Instant App or Full Android App
Branch.showInstallPrompt()
This methods shows an install prompt for the full Android app, allowing you an easy way to pass Branch referring deep data to the full app through the install process.

How to enforce policy from maas360 mdm to my android app

I am trying to enforce a policy on android app and my app is not able to understand that policy.
I have written a simple code where I am asking for a string from maas360 mdm.
Following is my Android manifest code snippet:
<receiver android:name=".GetRestrictionReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.APPLICATION_RESTRICTIONS_CHANGED"></action>
</intent-filter>
</receiver>
And following is my broadcast receiver:
public void onReceive(Context context, Intent intent) {
Log.d("Get Restriction", "on receive");
RestrictionsManager restrictionsManager = (RestrictionsManager) context.getSystemService(Context.RESTRICTIONS_SERVICE);
Bundle b = restrictionsManager.getApplicationRestrictions();
if(b.containsKey("siteName")) {
Log.d("Get Restriction", "Site name= "+b.getString("siteName"));
}
//String value = intent.getStringExtra("siteName");
}
Following is my app_restriction xml:
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<restriction
android:key="siteName"
android:title="SiteName"
android:restrictionType="string"
android:defaultValue="English">
</restriction>
</restrictions>
Unfortunately my broadcast is not receiving my policy from maas360 mdm.
Would you help me understand what am I missing from my code that will get me the policy?
If you check out this page:
https://developer.android.com/work/managed-configurations.html#listen-configuration
You'll see the following -
Note: The ACTION_APPLICATION_RESTRICTIONS_CHANGED intent is sent only to listeners that are dynamically registered, not to listeners that are declared in the app manifest.
I see that you are delaring the listener in the app manifest. It needs to be dynamically registered.

How to override the behavior of opening Appboy web activity in deeplink In App messge

I am facing a problem in override the On Click Behavior in Appboy deeplink
Please find the following data
1- Register Appboy in BaseActivity which is the parent activity for all Application Activities
#Override
protected void onResume() {
AppboyInAppMessageManager.getInstance().registerInAppMessageManager(this);
Appboy.getInstance(this).requestInAppMessageRefresh();
}
#Override
protected void onPause() {
AppboyInAppMessageManager.getInstance().unregisterInAppMessageManager(this);
}
2- Add the receivers in Manifest File as following
<receiver android:name="com.forsale.forsale.appboy.AppboyGcmReceiver"
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.forsale.forsale" />
</intent-filter>
</receiver>
<receiver
android:name="com.forsale.forsale.appboy.AppBoyOpenReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.forsale.forsale.intent.APPBOY_PUSH_RECEIVED" />
<action android:name="com.forsale.forsale.intent.APPBOY_NOTIFICATION_OPENED" />
</intent-filter>
</receiver>
Know I can send in app message using app boy dashboard, and receive the message, but when I click the message it open appboy web activity with the link
I need to override this behaviour to be able to get the link that I sent in In app message and parse some parameters from it and direct the use to an activity inside my app
I have tried the following
remove default app boy web activity from manifest file /// the app crash
implement the IInAppMessageManagerListener /// the app stop receiving any messages
Please note that the application call the onReceive method when trying to register appboy and print the log (action = REGISTRATION, RegId = "..."), but it never lo any other actions like RECEIVE, or OPEN
public void onReceive(Context context, Intent intent) {
AppboyLogger.i("AMIRA", String.format("Amira %s", intent.toString()));
String action = intent.getAction();
AppboyLogger.i("AMIRA", String.format("Amira %s", action));
Bundle bundle = intent.getExtras();
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
AppboyLogger.i("AMIRA", String.format("Amira %s", key + ":" + value.toString()));
}
}
The root of the problem is that we differentiate deep links and http links based on schema of the URI, so http (and some other schemes) links are detected as web links, and other formats are seen as deep links (see https://github.com/Appboy/appboy-android-sdk/blob/master/android-sdk-ui/src/com/appboy/ui/actions/ActionFactory.java).
We’ll consider how to instrument things for the use case you have, but in the meantime there’s a couple of ways you could solve the issue:
1) Create a deep link that is not also an http link. Everything should work if your link instead looks like, for example, forsale://mylink?a=b&2=3....etc.
2) Set a custom in-app message manager listener: https://documentation.appboy.com/Android/#in-app-message-customization. You can see an example of how we do this in our Droidboy sample app. In your case, you’d want to return defaults for everything but onInAppMessageButtonClicked and onInAppMessageClicked where you’d want to handle the link yourself if it’s of the format of your deep link. Your ticket indicates you’ve tried this, but I’d suggest starting with "the default one we create in the AppboyInAppMessageManager.java (#L608) in the Android SDK - and then just modifying the *clicked methods.
3) Download our UI code and modify the source. You could optionally download the Appboy Android SDK and modify the ActionFactory to handle your deep link in the way you want. Though, at the point you are going to do something like this, solution #2 is likely going to be a nicer one to implement and maintain.
Please let us know if one of these solutions works for you and if you have any other comments/questions.
Thanks,
Waciuma

Place Picker Automatically close after launch

I want to show place picker so that user can choose location of his/her own choice. But place picker child activity automatically closes after launch. I've check the API key multiple times and other permissions, everything is correct. Here is all the code. Please help!
task_location.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
PlacePicker.IntentBuilder intentBuilder = new PlacePicker.IntentBuilder();
Intent intent = intentBuilder.build(NewTaskActivity.this);
// Start the Intent by requesting a result, identified by a request code.
startActivityForResult(intent, 123);
} catch (GooglePlayServicesRepairableException e) {
GooglePlayServicesUtil
.getErrorDialog(e.getConnectionStatusCode(), NewTaskActivity.this, 0);
} catch (GooglePlayServicesNotAvailableException e) {
Toast.makeText(NewTaskActivity.this, "Google Play Services is not available.",
Toast.LENGTH_LONG)
.show();
}
}
});
And here is the menifest file.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
tools:replace="android:icon">
<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="AIzaSyAjM9hWUXm8vlABqFbM_fJfQgIFli8HP1E"/>
Please check the logcat of your app for 'PLACES_API_ACCESS_NOT_CONFIGURED' message. If this is the case, enabling the Google Places API for Android in your Google Developer Console for this project should solve your problem.
After A lot of debugging i solved it myself. The problem was package name..Android studio manage package name by itself on project creation. I change the package name in manifest and it was working perfectly fine. but when i get API key from google developers console for place picker, place picker automatically closes without a single character of error.
Then I change the package name by going into -> Module Settings -> Flavors and change the Application ID and it fix the problem.
Make sure that Google Places API is enabled for the API key that you are using in Google API console. For me, I am using the same API key that I use for maps. I just enabled the same key for places api also. That solved my problem.
Use this link to access the Google console: https://console.developers.google.com/flows/enableapi?apiid=placesandroid&reusekey=true
Solved problem by just changing the API key
You can create a new key from here
Instead of enabling the places API, Enable the places SDK for android. Worked for me.
Good Luck :)
Enable both places API as well as Places sdk

checking permissions in custom account authenticator

i have a custom authenticator, and i'd like to expose the user / password to other applications. to protect from any random app obtaining the credentials, i'd like to perform something like a permissions check in my custom authenticator's getAuthToken() method. what's the correct method?
i tried this,
int p = context.checkCallingPermission("com.whatever.AUTH");
if (p != PackageManager.PERMISSION_GRANTED) {
where "com.whatever.AUTH" is defined in the app hosting my authenticator,
<permission android:name="com.vmware.horizon.AUTH" />
however, in my test app that does not have a uses-permission in it's manifest, when i request the account,
AccountManagerFuture<Bundle> future = am.getAuthToken(new Account(
"com.whatever", "com.whatever"),
"com.whatever", new Bundle(), this,
new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
String token = result.getString(AccountManager.KEY_AUTHTOKEN);
}
}, handler);
i successfully obtain the auth token. debugging shows that the call through to my authenticator's getAuthToken() method happens, but the check permission call returned "granted".
EDIT: if i get the package name from the context i'm using to call checkCallingPermission() it is the package name of the app hosting the custom authenticator. if i get the calling PID, UID they are 0 and 1000, respectively.
any ideas?
When looking at the Android source code, I noticed that the account manager service sets the caller's pid and uid on the Bundle as AccountManager.KEY_CALLER_PID and AccountManager.KEY_CALLER_UID.
You can use getInt() on the bundle to find out the real caller's pid and uid in your getAppToken method.
One other useful bit of information that can be hard to find. The getAppToken method is often only called once since the account manager service caches the result. If you want to be able to manage the token more actively, you can disable caching by adding meta-data to your manifest entry:
<service android:name=".authenticator.AccountAuthenticatorService">
<meta-data android:name="android.accounts.AccountAuthenticator" android:resource="#xml/authenticator"/>
<meta-data android:name="android.accounts.AccountAuthenticator.customTokens" android:value="1"/>
</service>
Here is what the authenticator xml looks like:
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.your.account.type"
android:customTokens="true"
android:icon="#drawable/logo"
android:smallIcon="#drawable/logo"
android:label="#string/app_name_long"/>

Categories

Resources