GCM conflict between Android App and Android Library - android

I'm building a library that uses GCM. I was testing it with a sample app that implements GCM as well.
I have used same implementation for both except every one of them has its own sender ID
That's what I wrote for my sample app I'm testing the library with. I also wrote same thing for the library but with different names for the services:
<!-- GCM -->
<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="com.example.instabug" />
</intent-filter>
</receiver>
<service
android:name=".SampleInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name=".SampleGcmRegistrationIntentService"
android:exported="false"/>
<service
android:name=".SampleGcmListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
My problem is whenever I sent a push notification to my library the App receiver always catch it. the library receiver don't do anything.
Is there a way to resolve this issue?!

As far as I understand you have two services with same intent filter. In that case Android will pick the service with higher priority (foreground). If priority is the same - will pick random, i.e. just one service will receive the intent.
For your case best solution will be to use just one service and dispatch according to from (senderId) parameter of onMessageReceived() in your GcmListenerService.

I figured out someway to do that. In my Android library I gave the intent filter of GcmListenerService a higher priority than the one is in the Android app so that the GCM message received and processed by the library first.
<service
android:name=".SampleGcmListenerService"
android:exported="false">
<intent-filter priority="100">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
When the GCM message arrive to the library's GcmListenerService you have to forward to the android app if it's irrelevant to the library. Since I'm making a library that can be used by anyone in the future. I will not know where can I find the GcmListenerService in the the app module. All I can do is to use reflection to get all classes in the app module and see which one has GcmListenerService as a super class and then starting a wakeful service to that class.
Here what I did:
#Override
public void onMessageReceived(String from, Bundle data) {
if (!from.equalsIgnoreCase("51XXXXXXXX")) {
String[] classes = getClassesOfPackage(getPackageName());
for (int i = 0; i < classes.length; i++) {
String sClassName = classes[i];
try {
Class classToInvestigate = Class.forName(sClassName);
String superClassName = classToInvestigate.getSuperclass().getName();
if (superClassName.equalsIgnoreCase("com.google.android.gms.gcm.GcmListenerService")) {
//sending intent to the wakeful app's service
forwardGcmToApp(from, data, sClassName);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
//TODO: fire the polling service
String message = data.getString("message");
}
}
/**
* Called to get list of classes included in the current project
*
* #param packageName the name of application package
* #return array of classes' names
*/
private String[] getClassesOfPackage(String packageName) {
ArrayList<String> classes = new ArrayList<>();
try {
String packageCodePath = getPackageCodePath();
DexFile df = new DexFile(packageCodePath);
for (Enumeration<String> iter = df.entries(); iter.hasMoreElements(); ) {
String className = iter.nextElement();
if (className.contains(packageName)) {
classes.add(className);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes.toArray(new String[classes.size()]);
}
/**
* Called to forward Gcm content to the App {#link GcmListenerService}
*
* #param from Gcm sender ID
* #param data bundle received from Gcm
* #param className Class name that extends {#link GcmListenerService}
*/
private void forwardGcmToApp(String from, Bundle data, String className){
Intent intent = new Intent();
intent.setAction("com.google.android.c2dm.intent.RECEIVE");
data.putString("from", from);
data.putString("message_type", null);
intent.putExtras(data);
intent.setComponent(new ComponentName(getPackageName(), className));
GcmReceiver.startWakefulService(getApplicationContext(), intent);
}

Related

How can I get the MobileFirst Foundation SDK to ignore Push Notifications sent by sources other than MobileFirst?

The MobileFirst Foundation SDK push notification receiver doesn't appear to be able to differentiate between notifications coming from MobileFirst and those from other sources.
We are trying to implement push notification in our app such that it can receive notifications from multiple sources. But what we've observed is that, while other cloud push providers' SDKs on process push notifications sources from that provider, the MobileFirst SDK processes all push notifications received by the device. This causes notifications sent from the cloud providers to be displayed twice on the device.
Some additional details:
This seems true regardless of the 3rd party cloud provider. We've tried 5 and all ignore MobileFirst notifications, however MobileFirst processes notifications from all of them.
GCM sender ID is the same for MobileFirst as for the other providers.
We are building native Android and iOS applications.
MobileFirst does not support this functionality out of the box, however because the other push services don't use the MobileFirst adapter used to send notifications via MobileFirst, the key is to add a property to the notification payload that can tell the device whether or not to show the notification.
So for instance, one solution would be to add a custom property in the adapter with the value "mfp" to the payload like this:
notification = WL.Server.createDefaultNotification(notificationText,
badgeDigit, {custom:"mfpush"});
Then in MyListener.java in the Android native code, add an "if" statement in the onReceive() function. This will handle the case when the application is running in the foreground:
public void onReceive(String props, String payload) {
JSONObject jsonObject;
JSONObject payloadJSON;
String notification = "";
String payloadNotif = "";
try {
// get payload from MFP adapter: custom property
payloadJSON = new JSONObject(payload);
payloadNotif = payloadJSON.getString("custom");
// if the payload "custom" property is "mfp", show the alert,
// if not, don't show the alert
if (payloadNotif.contains("mfp")) {
jsonObject = new JSONObject(props);
notification = jsonObject.getString("alert");
}else{
return;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MainActivity.alertMsg("Notification", notification);
}
In the case where the application is running in the background, a new class needs to be created that extends com.worklight.wlclient.push.WLBroadcastReceiver and overrides the receive method. Create a CustomBroadcastReceiver class that extends WLBroadCastReceiver and overrides the onReceive method to call CustomGCMIntentService
public class CustomBroadcastReceiver extends WLBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent.setClassName(context,
CustomGCMIntentService.class.getName());
WakefulIntentService.sendWakefulWork(context, intent); } }
Then in CustomGCMIntentService, extend the MFP GCMIntentService class and override the two notify methods to check of the push came from MFP:
package com.sample.eventsourcenotificationsandroid.custom;
import android.content.Context;
import android.content.Intent;
import com.worklight.wlclient.push.GCMIntentService;
import org.json.JSONObject;
public class CustomGCMIntentService extends GCMIntentService {
#Override
public void notify(Context context, String tickerText) {
super.notify(context, tickerText);
}
#Override
public void notify(Context context, String alert, int badge, String
sound, Intent intent) {
if(isMobileFirstNotification(intent)) {
super.notify(context, alert, badge, sound, intent);
} }
#Override
public void notify(Context context, Message message, Intent intent) {
if(isMobileFirstNotification(intent)) {
super.notify(context, message, intent);
} }
private boolean isMobileFirstNotification(Intent intent) {
Message message = intent.getParcelableExtra("message");
JSONObject payload = message.getPayload();
return payload.optBoolean("mfpush", false);
} }
The way you're checking for notifications from MFP is by checking that the mfppush key as a value of true in the notification payload.
data: {
badge: "",
alert: "YourMessageContent",
sound: "your sound",
payload:{
mfpush: true
} }
Lastly, the manifest needs to be updated to use the new class instead of com.worklight.wlclient.push.WLBroadcastReceiver as follows:
<service android:name="com.worklight.wlclient.push.GCMIntentService" />
<receiver android:name="com.worklight.wlclient.push.WLBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<!-- removed intent-filter for com.google.android.c2dm.intent.RECEIVE
-->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.sample.eventsourcenotificationsandroid" />
</intent-filter>
</receiver>
<!-- start custom service and receiver -->
<service android:name="com.sample.eventsourcenotificationsandroid.custom.
CustomGCMIntentService" />
<receiver android:name="com.sample.eventsourcenotificationsandroid.custom.CustomB roadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.sample.eventsourcenotificationsandroid" />
</intent-filter>
</receiver>
<!-- end custom service and receiver -->

Referral linking in Android like mCent application

I have to implement the referral linking functionality in my application like mCent application. For that I have done the following lines of code.
My application Manifest file. In the <application >..... </application> , I have done some entries for it.
<service android:name="com.google.android.gms.analytics.CampaignTrackingService" />
<receiver
android:name=".receivers.InstallReceiver"
android:exported="true" >
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
And My BrodcastRecevier class is as follow , please check it.
public class InstallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String rawReferrer = intent.getStringExtra("referrer");
if (rawReferrer != null) {
trackReferrerAttributes(rawReferrer, context);
}
}
private void trackReferrerAttributes(String rawReferrer, Context context) {
String referrer = "";
try {
referrer = URLDecoder.decode(rawReferrer, "UTF-8");
} catch (UnsupportedEncodingException e) {
return;
}
if (Strings.isNullOrEmpty(referrer)) {
return;
}
Uri uri = Uri.parse('?' + referrer); // appends ? for Uri to pickup query string
String memberCode;
try {
referringMember = uri.getQueryParameter("mcode");
} catch (UnsupportedOperationException e) {
return;
}
SharedPreferences.Editor editor = context.getSharedPreferences(
BuildConfig.PACKAGE_NAME, Context.MODE_PRIVATE).edit();
if (!Strings.isNullOrEmpty(memberCode)) {
editor.putString(Constants.REFERRER_CODE, memberCode);
}
String referralMedium = uri.getQueryParameter("tc");
if (!Strings.isNullOrEmpty(referralMedium)) {
editor.putString("referral_medium", referralMedium);
}
editor.apply();
}
}
But i am not receiving any referral from the above code...
I have created the refferal link like this
https://play.google.com/store/apps/details?id=tv.CaseGaurd&referrer=ravindrakushwaha
Is there is any error in my referral link above OR friends , what am i doing wrong in my BroadcastRecevier class or in Manifest file
From this documentation I found that the action filter is (in manifest):
<!-- Used for install referrer tracking-->
<receiver android:name="YOUR_RECEIVER"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
Also be sure that your Receiver is in that real package ".receivers.InstallReceiver", but package com.example.app.receivers;... is your package really com.example.app?
(I considered you to be using the Google Play Store app)... also, about your downvotes, this is likely to bad wording on your question, or that you are not showing effort about your question, finally, note that this is a "free to use community forum", and that people are random...
Finally, put a breakpoint in the Receiver, send a broadcast (using adb for instance), and test that you are really not getting the broadcast.

GCM and Parse notification conflict

I need my android app to work with two push services, GCM and parse.
My problem is that I can't find a way for register correctly to Parse, get parse notification and GCM notification too. I can reach all these things individually, but never together.
My current implementation looks this way:
<!-- GCM BradcastReceiver & Service -->
<service android:name=".GcmIntentService"
android:enabled="true"/>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter
android:priority="100"> <!-- higher priority to GCM messages -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.twentyLines.GCM_NOTIFICATION_ACTION" />
<category android:name="com.twentyLines.app" />
</intent-filter>
</receiver>
This is the broadcastReceiver for GCM, and the one below is the other receiver for parse:
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter android:priority="0">
<!--<action android:name="com.google.android.c2dm.intent.RECEIVE" />-->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.twentyLines.app" />
</intent-filter>
</receiver>
<!-- Can remove this if application is already registered for GCM -->
<receiver android:name="com.parse.ParseBroadcastReceiver" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
I've tried to add a custom broadcast receiver to handle just parse notification, so I can avoid it to handle GCM too. I've done it like this:
<receiver android:name="com.twentyLines.app.ParseBroadcastReceiver" android:exported="false" >
<intent-filter>
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
This is the implementation of my BroadcastReceiver for GCM, that avoid parse notification to be displayed.
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
boolean isFromParse = intent.getExtras().get("action").equals("com.twentyLines.PARSE_NOTIFICATION_ACTION");
if (isFromParse)
return;
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_CANCELED);
}
}
And this is the implementation for my PARSE custom BroadcastReceiver that SHOULD avoid GCM to be showed.
The parse custom receiver is never invoked, I think because the com.parse.GcmBroadcastReceiver handle the notification itself instead of pass them.
The result is that, when I send a notification from my server to GCM receiver, this is retrieved from both, and double notification is showed.
(double is already good, every time I uninstall and reinstall my app Parse register another user.. the "UniqueId" I send to parse every time is not so UNIQUE for them).
What have I tried?
I'm really getting crazy, I've tried about everything.
- I've read all related questions, and no one is good for me;
- I've tried to remove the parse receiver, and this cause a parse exception (so doesn't register to parse)
- I've tried to set the intent to RESULT_CANCELED, but in some way parse get it before GCM, so isn't working when I use GCM.
- I've changed about all using cowboy-coding, and it still not work...
Any help will be really welcome. Thank you guys!
EDIT - ADD WORKING MANIFEST
<!-- GCM BradcastReceiver & Service -->
<service android:name=".GcmIntentService"
android:enabled="true"/>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter
android:priority="2"> <!-- higher priority to GCM messages -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.twentyLines.GCM_NOTIFICATION_ACTION" />
<category android:name="com.twentyLines.app" />
</intent-filter>
</receiver>
<!-- Parse service broacastReceiver and receiver. -->
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter android:priority="1">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.twentyLines.app" />
</intent-filter>
</receiver>
<!-- Can remove this if application is already registered for GCM -->
<receiver android:name="com.parse.ParseBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
<receiver android:name="com.twentyLines.app.ParseBroadcastReceiver" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="com.twentyLines.PARSE_NOTIFICATION_ACTION" />
</intent-filter>
</receiver>
EDIT 2: HOW I REGISTER PARSE AND GCM
I register Parse in my application class:
Parse.initialize(this, PARSE_APP_KEY_VALUE, PARSE_CLIENT_KEY_VALUE);
PushService.setDefaultPushCallback(getApplicationContext(), MainActivity.class);
final ParseInstallation installation = ParseInstallation.getCurrentInstallation();
final String androidId = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
installation.put("UniqueId", androidId);
installation.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
Log.d("Parse installation saved in background", "If operation successfull, 'e' have to be NULL e= " + e);
}
});
}
}, 5000
);
And I get gcm registration_id in my MainActivity:
// Check if there is a saved registration_id in shared_prefs,
// or if app version has changed
private String getSavedRegistrationId() {
final SharedPreferences gcmShared = getGCMSharedPrefss();
String registrationId = gcmShared.getString(Constant.GCM_REGISTRATION_ID_KEY, "");
if (registrationId.isEmpty()) {
Log.i("GCM", "Registration not found.");
return "";
}
int registeredVersion = gcmShared.getInt(Constant.APP_VERSION_KEY, Integer.MIN_VALUE);
int currentVersion = getAppVersion(this);
if (registeredVersion != currentVersion) {
clearSavedGCMRegistrationId();
Log.i("GCM", "App version changed.");
return "";
}
return registrationId;
}
// If there isn't, request one
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg;
try {
if (_gcm == null) {
_gcm = GoogleCloudMessaging.getInstance(MainActivity.this);
}
String regid = _gcm.register(Constant.GCM_SENDER_ID);
msg = "Device registered, registration ID=" + regid;
sendRegistrationIdToBackend(regid);
storeRegistrationId(regid); // Save reg_id to shared
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the startupLoggedUser to click a button again, or perform
// exponential back-off.
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
Log.d("GCM registration", msg);
}
}.execute(null, null, null);
}
We have two broadcast receivers here to listen c2dm intent
.GcmBroadcastReceiver : lets call this as GCM receiver... Parse Push will never come to this receiver.
com.parse.GcmBroadcastReceiver : lets call this as Parse receiver
As you have given higher priority to GCM receiver, broadcast will come to GCM receiver first and then to Parse receiver. This does not guarantee that Broadcast will not go to Parse receiver. You need to add abortBroadcast(); as last line in onReceive method to make sure that Parse receiver is not triggered when we have GCM receiver working.
As per Parse Push notification guidelines, Push is received with a specific intent action. Data is sent to broadcast receiver registered with that action.
In your case, if push is received with action "com.twentyLines.PARSE_NOTIFICATION_ACTION", you can have a custom broadcast receiver to listen to this action. In that broadcast receiver you can fetch data by below code,
try {
String action = intent.getAction();
String channel = intent.getExtras().getString("com.parse.Channel");
JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
Log.d(TAG, "got action " + action + " on channel " + channel + " with:");
Iterator itr = json.keys();
while (itr.hasNext()) {
String key = (String) itr.next();
Log.d(TAG, "..." + key + " => " + json.getString(key));
}
} catch (JSONException e) {
Log.d(TAG, "JSONException: " + e.getMessage());
}
When there is GCM push, this custom receiver will never get broadcast event as the C2DM broadcast is being aborted in GCM receiver (".GcmBroadcastReceiver")
Hope This Helps!

Android - The best way to keep the broadcastreceiver working

I want my application to work and to listen for incoming Intents even if the activity is closed. What is the best way to do it?
I have a receiver registered on the manifest:
<receiver
android:name="com.farawayapp.background.Receiver"
android:exported="false" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.intent.action.PACKAGE_CHANGED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
And the BroadcastReceiver class is:
public class Receiver extends BroadcastReceiver implements Variables {
CheckConexion cc;
#Override
public void onReceive(Context contxt, Intent intent) {
// Cuando hay un evento, lo diferenciamos y hacemos una acción.
if (intent.getAction().equals(SMS_RECEIVED)) {
Sms sms = new Sms(null, contxt);
sms.uploadNewSms(intent);
} else if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
/*
* try { new PhoneState(contxt).battery(intent.getIntExtra("level",
* 0)); } catch (JSONException e) { e.printStackTrace(); }
*/// Nothing at the moment
} else if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
Database db = new Database(contxt);
if (db.open().Preferences(4)) {
Uri data = intent.getData();
new ListApps(contxt).import_app(intent, contxt, data,
intent.getAction());
}
db.close();
} else if (intent.getAction().equals(
ConnectivityManager.CONNECTIVITY_ACTION)) {
cc = new CheckConexion(contxt);
if (cc.isOnline()) {
Database db = new Database(contxt);
db.open();
if (db.move() == 1) {
new UploadOffline(contxt);
}
db.close();
}
}
}
}
Thanks...
If you register a BroadcastReceiver to receive broadcasts then it will be invoked even if user doesn't work with your application at the time (none of your application's activities is in foreground). Although, there are some pitfalls that you probably want to think about:
Most of the intents are not broadcasted when device is asleep. There are only several events that will wake up your device (such as incoming sms, incoming call, pushed notification from Google Cloud Messaging server, etc.). Thus, if want your application to do some work when device is asleep you should consider AlarmManager to set alarms that will regularly invoke your application.
If you want to do some work in background, you probably want to use WakeLock to prevent the device from sleeping (and CPU from turning off). This is a good sample from CommonWare that shows how to use WakeLock and provides you with nice library to ease your life: https://github.com/commonsguy/cwac-wakeful. Although, you should be careful with WakeLock because it can drain battery.

Android referral tracking does not work

I am attempting to get Android Referral tracking to work. I am following the only documentation I have found here http://code.google.com/mobile/analytics/docs/android/#referrals I have the following in my android manifest file
<receiver
android:name="com.google.android.apps.analytics.AnalyticsReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<receiver android:name="com.package.Receiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<uses-sdk android:minSdkVersion="4"/>
com.package.Receiver starts with:
public void onReceive(Context paramContext, Intent paramIntent) {
String str1 = paramIntent.getStringExtra("referrer");
Log.i("myapp", "action: '" + paramIntent.getAction() + "'
referrer string: '" + str1 + "'");
Also with a little bit of decompiling com.google.android.apps.analytics.AnalyticsReceiver has the following code in it:
public void onReceive(Context ctx, Intent intent)
/* */ {
/* 24 */ String referrer = intent.getStringExtra("referrer");
/* */
/* 26 */ if ((!
("com.android.vending.INSTALL_REFERRER".equals(intent.getAction())))
|| (referrer == null))
/* */ {
/* 28 */ return;
/* */ }
/* */
/* 31 */ String formattedReferrer = formatReferrer(referrer);
/* */
/* 33 */ if (formattedReferrer != null) {
/* 34 */ PersistentEventStore store = new
PersistentEventStore(ctx);
/* 35 */ store.setReferrer(formattedReferrer);
/* 36 */ Log.d("googleanalytics", new
StringBuilder().append("Stored
referrer:").append(formattedReferrer).toString());
/* */ } else {
/* 38 */ Log.w("googleanalytics", "Badly formatted referrer, ignored");
/* */ }
/* */ }
Note the two lines 36 and 38 that Log "googleanalytics" I have tried pushing the above app to the market, downloading it on my Nexus One (after uninstalling a previous version of the app). I have generated a link using the google page I linked to at the beginning of this post
http://www.google.com/url?sa=D&q=http://market.android.com/search%3Fq%3Dpname:com.package.app%26referrer%3Dutm_source%253Dgoogle%2526utm_medium%253Dcpc%2526utm_term%253Drunning%25252Bshoes%2526utm_content%253Dcontent1%2526utm_campaign%253Dslogan&usg=AFQjCNFctwqk1WgWl0bhiIBNVqy3U4OPRw
I attached logcat to my Nexus One while I download the app from that link, I do not see any logs from "googleanalytics" or "myapp". The rest of the google analytics library does work for my app. I.E. I see records on google analytics about pages hits etc. However all the traffic sources are "Direct Traffic". I am at a loss as to what is going on. Does anyone
have any insight into what I might be doing wrong?
As is often the case I found my own answer. My problem was in my AndroidManifest.xml
I had the following in my manifest:
<manifest>
<application>
</application>
<receiver>
</receiver>
<uses-sd/>
</manifest>
The receiver tag was in the wrong spot. It should look like this
<manifest>
<application>
<receiver>
</receiver>
</application>
<uses-sd/>
</manifest>
I am now seeing the logs I expect to when I install the app. In a few hours hopefully Google Analytics will have the data as well.
I have explore quite a lot the referral tracker with analytics for android. You don't need to put the app in the market you can just send a broadcast intent.
Intent i = new Intent("com.android.vending.INSTALL_REFERRER");
i.setPackage(com.package.yourapp)
//referrer is a composition of the parameter of the campaing
i.putExtra("referrer", referrer);
sendBroadcast(i);
There can be only one BroadcastReceiver for an action. In your AndroidManifest.xml, you have two listening for com.android.vending.INSTALL_REFERRER.
If you want to your receiver AND the Google Analytics receiver to both handle the intent, make your receiver a subclass of AnalyticsReceiver, like this:
import com.google.android.apps.analytics.AnalyticsReceiver;
class Receiver extends AnalyticsReceiver {
#Override
void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
// Add your custom handling here
}
}
Then make sure yours is the only receiver in AndroidManifest.xml:
<receiver android:name="com.package.Receiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>

Categories

Resources