App hangs when install from play store via referrer - android

I have an android application in play store. after installing it from referrer url and opens directly from play store, it hangs and apaplication crashes, something like doing to much work on UI thread,I have two broadcast receivers in my manifest for INSTALL_REFERRER one is for Analytic purpose and another is for setting some alarm. for analytic purpose I'm extracting utm source, medium, campaign id... it is very light weighted operation but still I am doing it on an IntentService,
Code
#Override
protected void onHandleIntent(Intent intent) {
getUtmValuesAndSave(UtmCreateService.this, intent);
}
private void getUtmValuesAndSave(Context context, Intent intent) {
String referrer = intent.getStringExtra(Constants.UTM_REFERRER);
String source = getSourceFromReferrer(referrer);
saveSourceInPreference(context, source);
}
private static String getSourceFromReferrer(String referrer) {
StringBuilder sourceBuilder = new StringBuilder();
String source = null;
try {
referrer = URLDecoder.decode(referrer, "UTF-8");
String[] utms = referrer.split("&");
String utm = getUtmValue(utms, Constants.UTM_SOURCE);
sourceBuilder.append(Constants.UTM_SOURCE).append("=").append(utm).append("&");
utm = getUtmValue(utms, Constants.UTM_CAMPAIGN);
sourceBuilder.append(Constants.UTM_CAMPAIGN).append("=").append(utm).append
("&");
utm = getUtmValue(utms, Constants.UTM_ANID);
sourceBuilder.append(Constants.SERVER_UTM_ADGROUPID).append("=").append(utm);
} catch (Exception e) {
e.printStackTrace();
}
source = sourceBuilder.toString();
return source;
}
/**
* read utm value for the given key
*
* #param utms utm string array, contains all the utm fields
* #param key key
* #return value of the key in utm
*/
private static String getUtmValue(String[] utms, String key) {
String utm = null;
boolean foundUtm = false;
for (String utm1 : utms) {
utm = utm1;
if (utm.contains(key)) {
foundUtm = true;
utm = utm.split("=")[1];
break;
}
}
if (!foundUtm) {
utm = "Null";
}
return utm;
}
** Manifest **
<receiver
android:name=".receiver.AnalyticsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.AlarmStartReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER"/>
</intent-filter>
</receiver>
what could be the issue here ? if I install the app directly from play store (without referrer url, then it works fine). I have checked the logcat logs, and I saw the receiver calls multiple times
EDIT
I have tested app with this adb command adb shell am broadcast -a com.android.vending.INSTALL_REFERRER --es "referrer" "utm_source%3Dgoogle%26utm_medium%3Dcpc%26utm_term%3Dtest%2520fund%26utm_content%3Dnew%2520ad%26utm_campaign%3Dtest%26anid%3Dadmob; and I found it repeatedly calls INSTALL_REFERRER receiver.
UPDATE, Log when install from play store
MultipleInstallBroadcastReceiver.onReceive(MultipleInstallBroadcastReceiver.java:31)
02-27 17:11:46.840 21946-21946/my.package.name W/logd: Dropped 2
02-27 17:11:46.840 21946-21946/my.package.name E/art: at my.package.name.receiver.CommonAnalyticsTrackingReceiver.onReceive(CommonAnalyticsTrackingReceiver.java:29)
02-27 17:11:46.840 21946-21946/my.package.name W/logd: Dropped 3
02-27 17:11:46.840 21946-21946/my.package.name E/art: at my.package.name.receiver.CommonAnalyticsTrackingReceiver.onReceive(CommonAnalyticsTrackingReceiver.java:29)
02-27 17:11:46.840 21946-21946/my.package.name W/logd: Dropped 2
02-27 17:11:46.840 21946-21946/my.package.name E/art: at com.appsflyer.MultipleInstallBroadcastReceiver.onReceive(MultipleInstallBroadcastReceiver.java:31)
02-27 17:11:46.840 21946-21946/my.package.name W/logd: Dropped 2
02-27 17:11:46.840 21946-21946/my.package.name E/art: at my.package.name.receiver.CommonAnalyticsTrackingReceiver.onReceive(AnalyticsTrackingReceiver.java:29)
02-27 17:11:46.840 21946-21946/my.package.name W/logd: Dropped 3
this is the log when install from play store, it comes around 1000 times.

Related

android : Get or create unique id for each device

I am developing an application using api 14 (android 4.0).
in manifest:
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />
I want to get an unique id from each device (or create one) that could be the same even after reboot the device. But it is important that the id be different even for 2 same devices. How can i do that?
You can use device's IMEI number as unique Id.
You want to call android.telephony.TelephonyManager.getDeviceId().
This will return whatever string uniquely identifies the device (IMEI on GSM, MEID for CDMA).
You'll need the following permission in your AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
You can generate different device token using GCM....
And this device token will remain same even if you will uninstall and again installed the application or after factory setting.. you have to follow some 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 the client project; and API server key (created at Credentials), which will be used as API_KEY in the server project.
Create a new simple Android project for server side (with basic source code as my answer in the following links).
Create a new simple Android project for client side (with basic source code as my answer in the following links, 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 (or write code to send this token to server app).
You can read more at the following questions, one of them you have read before with one of your previous questions:
How to implement a GCM Hello World for Android using Android Studio
Adding Google Cloud Messagin (GCM) for Android - Registration process
Try this one String android_id = Settings.Secure.getString(getApplicationContext().getContentResolver(),
Settings.Secure.ANDROID_ID);
Here android_id is the unique Id for each device.
Try this code
String UniqueDeviceId = AndroidDeviceIdentifier.getUniqueDeviceIdentifier(context);
Add this class too.
final class AndroidDeviceIdentifier {
private AndroidDeviceIdentifier() {
// hidden constructor of singleton
}
/**
* Returns a stable identifier for the current device.
*
* #param ctx The application's Context
* #return The unique device identifier
* #throws IllegalStateException If the device's identifier could not be determined
*/
public static String getUniqueDeviceIdentifier(#NonNull final Context ctx) throws IllegalStateException {
try {
return getDeviceUUID(ctx);
} catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
throw new IllegalStateException("Could not determine device identifier", e);
}
}
private static String getDeviceUUID(Context ctx) throws UnsupportedEncodingException, NoSuchAlgorithmException {
byte[] hash = makeHash(getMac(ctx), getSerialNumber(ctx));
return createUUIDFromHash(hash);
}
private static String createUUIDFromHash(byte[] hash) {
return UUID.nameUUIDFromBytes(hash).toString().toLowerCase(); // Server side wants lower cased UUIDs
}
private static byte[] makeHash(final String mac, final String serialNumber) throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest sha;
sha = MessageDigest.getInstance("SHA-256");
sha.reset();
sha.update(mac.getBytes("UTF-8"));
sha.update(serialNumber.getBytes("UTF-8"));
return sha.digest();
}
private static String getSerialNumber(Context context) {
String serialNumber = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
if (serialNumber == null) {
serialNumber = "0000000000000000";
}
return serialNumber;
}
private static String getMac(Context context) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
String mac = wifiManager.getConnectionInfo().getMacAddress();
if (mac == null) {
mac = "000000000000";
}
return mac;
}
You will get a unique device id. Ping me if u have any questions
Try out this code below ,this device id is constant and even if you uninstall the app and reinstall this id remains constant and you can use it to retrieve the user data from database as well.
final String android_id = Settings.Secure.getString(getApplicationContext().getContentResolver(),
Settings.Secure.ANDROID_ID);
Just paste this code in your main activity or any function and can store the ID generated in the shared Preference for later use.

Android Analytics Campaign Tracking

I want to know how my android users are getting to the play store link of my app.
To do this I have integrated the Google Analytics API, but the installation intent isn't called and I can't get the utm_source, utm_campaign ... parameters in the link built with the google play url builder
So i'm trying to do this with my custom intent like this :
1: The android manifest :
<receiver android:name="com.appehour.InstallReceiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" android:exported="true"/>
</intent-filter>
</receiver>
2: the InstallReceiver class
public class InstallReceiver extends BroadcastReceiver {
private String
utm_compaign ,
utm_source,
utm_medium,
utm_term,
utm_content,
deviceId;
private static String url, installTimeStamp;
public static final String PREF_TRACK_INSTALL_RECEIVER_DATAS = "datas_receiver_install",
PREF_DEVICE_ID = "pref_device_id",
PREF_COMPAIGN = "pref_compaign",
PREF_SOURCE = "pref_source",
PREF_MEDIUM = "pref_medium",
PREF_TERM = "pref_term",
PREF_CONTENT = "pref_content",
PREF_INSTALL_TIME_STAMP = "pref_install_time_stamp",
PREF_DATA_STORED = "pref_datas_stored";
protected JSONObject jsonSend , jsonObjRecv;
private boolean installParamsSend = false;
#SuppressLint("NewApi")
#Override
public void onReceive(Context context, Intent intent) {
TimeZone timeZone = TimeZone.getDefault();
installTimeStamp = String.valueOf(System.currentTimeMillis()) ;
deviceId = Secure.getString(context.getContentResolver(),Secure.ANDROID_ID);
//****************************** Tris des datas reçus par le brodcast ********************************//
String referrer = intent.getStringExtra("referrer");
//the paramters are separated by this : %3D
// uriTokens store all the paramaters with her value
String[] uriTokens = referrer.split("%3D");
for(int i=0;i<uriTokens.length;i++){
//the parameter name and the value are separated
String[] valTokens = uriTokens[i].split("%26");
if (valTokens[0].equals("utm_compaign"))
utm_compaign = valTokens[1];
else if (valTokens[0].equals("utm_source"))
utm_source = valTokens[1];
else if (valTokens[0].equals("utm_medium"))
utm_medium = valTokens[1];
else if (valTokens[0].equals("utm_term"))
utm_term = valTokens[1];
else if (valTokens[0].equals("utm_content"))
utm_content = valTokens[1];
}
//******************************************************************************************************//
Log.d(InstallReceiver.this.getClass().getSimpleName(),
"utm_compaign = "+utm_compaign+
"| utm_source = "+utm_source+
"| utm_medium = "+utm_medium+
"| utm_term = "+utm_term+
"| utm_content = "+utm_content+
"| device_id = "+deviceId+
"| installTimeStamp ="+installTimeStamp);
When I simulate the app installation with adb shell:
adb shell am broadcast -a com.android.vending.INSTALL_REFERRER -n com.appehour.jdm/com.appehour.InstallReceiver --es "referrer" "utm_source%26testSource%3Dutm_compaign%268656"
I get my data. But when I put my app on the store, the data are not recovered.
Any idea what the issue is?
Thanks

how to get referrer using google track in android?

I want to implement install referrer track and want referrer parameter and store in back end database i have seen many exmple or question as on like Get Android Google Analytics referrer tag or Android Google Analytics Campaign tracking not appearing but not get a way i have generated links to and try the code
package SimpleDemo.ReferralTrack;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
public class ReferralReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
// Workaround for Android security issue: http://code.google.com/p/android/issues/detail?id=16006
try
{
final Bundle extras = intent.getExtras();
if (extras != null) {
extras.containsKey(null);
}
}
catch (final Exception e) {
return;
}
Map<String, String> referralParams = new HashMap<String, String>();
// Return if this is not the right intent.
if (! intent.getAction().equals("com.android.vending.INSTALL_REFERRER")) { //$NON-NLS-1$
return;
}
String referrer = intent.getStringExtra("referrer"); //$NON-NLS-1$
if( referrer == null || referrer.length() == 0) {
return;
}
try
{ // Remove any url encoding
referrer = URLDecoder.decode(referrer, "x-www-form-urlencoded"); //$NON-NLS-1$
}
catch (UnsupportedEncodingException e) { return; }
// Parse the query string, extracting the relevant data
String[] params = referrer.split("&"); // $NON-NLS-1$
for (String param : params)
{
String[] pair = param.split("="); // $NON-NLS-1$
referralParams.put(pair[0], pair[1]);
}
ReferralReceiver.storeReferralParams(context, referralParams);
}
private final static String[] EXPECTED_PARAMETERS = {
"utm_source",
"utm_medium",
"utm_term",
"utm_content",
"utm_campaign"
};
private final static String PREFS_FILE_NAME = "ReferralParamsFile";
/*
* Stores the referral parameters in the app's sharedPreferences.
* Rewrite this function and retrieveReferralParams() if a
* different storage mechanism is preferred.
*/
public static void storeReferralParams(Context context, Map<String, String> params)
{
SharedPreferences storage = context.getSharedPreferences(ReferralReceiver.PREFS_FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = storage.edit();
for(String key : ReferralReceiver.EXPECTED_PARAMETERS)
{
String value = params.get(key);
if(value != null)
{
editor.putString(key, value);
}
}
editor.commit();
}
/*
* Returns a map with the Market Referral parameters pulled from the sharedPreferences.
*/
public static Map<String, String> retrieveReferralParams(Context context)
{
HashMap<String, String> params = new HashMap<String, String>();
SharedPreferences storage = context.getSharedPreferences(ReferralReceiver.PREFS_FILE_NAME, Context.MODE_PRIVATE);
for(String key : ReferralReceiver.EXPECTED_PARAMETERS)
{
String value = storage.getString(key, null);
if(value != null)
{
params.put(key, value);
}
}
return params;
}
}
After that i have try in my activity
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(DemoActivity.this);
String referrers1 =preferences.getString("ga_campaign", "0");
Map<String, String> retrieveReferralParams=ReferralReceiver.retrieveReferralParams(DemoActivity.this);
String referrers2= retrieveReferralParams.get("utm_source");
String referrers3= retrieveReferralParams.get("utm_medium");
String referrers4= retrieveReferralParams.get("utm_term");
String referrers5= retrieveReferralParams.get("utm_content");
String referrers6= retrieveReferralParams.get("utm_campaign");
tv.setText(referrers1+" "+referrers2+" "+referrers3+" "+referrers4+" "+referrers5+" "+referrers6+" ");
on button click but not get desired output
i want something like from
"https://play.google.com/store/apps/details?id=com.lifestreet.android.TestInstallationIntent&referrer=bb%3DAAAAAAAAAA&feature=search_result%22"
Ans
referrer=bb
any help me highly appreciated
Thanks in advance.
Not sure that Google lets you send arbitrary information. Try using the generator to create the url.
https://developers.google.com/analytics/devguides/collection/android/devguide#google-play-builder
I have had a similar issue. Found it to be lifecycle problem: the onReceive of the install_referrer receivers are invoked AFTER my app's onResume(), on the SAME main thread, so any attempt to read the referrer file during onResume() fails. Here is the logcat to prove it, this was 100% reproducible over and over on 2 devices using Android 4.2.1 and 4.4.2:
First, play store broadcasts the referrer to the package on a separate (store) process:
11-04 14:17:51.558: D/Finsky(1737): [1] ReferrerRebroadcaster.doBroadcastInstallReferrer: Delivered referrer for com.xxx.demo
The app onResume() - still no activation of the broadcast receivers! S
11-04 14:17:51.888: D/XXX Main Activity(22730): onResume
The app tries to read the referrer (which the receivers should have stored using getSharedPreferences.putString):
11-04 14:17:51.958: I/XXX(22730): Extracted install referrer:
Only now the receivers are invoked on the main thread and will shortly try to write the referrer to a file:
11-04 14:17:51.918: I/XXX(22730): Received install referrer: abcdefg
As you can see, onResume() has no chance to actually read the file, so the extraction yields nothing. However, if I close the app and reopen it, onResume is now able to find the file and the referrer string gets processed - but not on first launch :)
Hope this helps!
Google Analytics uses arbitrary constants in their SDK.
for campaing_source is &cs.

install / uninstall APKs programmatically (PackageManager vs Intents)

My application installs other applications, and it needs to keep track of what applications it has installed. Of course, this could be achieved by simply keeping a list of installed applications. But this should not be necessary! It should be the responsibility of the PackageManager to maintain the installedBy(a, b) relationship. In fact, according to the API it is:
public abstract String getInstallerPackageName(String packageName) -
Retrieve the package name of the application that installed a package. This identifies which market the package came from.
The current approach
Install APK using Intent
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
startActivity(intent);
Uninstall APK using Intent:
Intent intent = new Intent(Intent.ACTION_DELETE, Uri.fromParts("package",
getPackageManager().getPackageArchiveInfo(apkUri.getPath(), 0).packageName,null));
startActivity(intent);
This is obviously not the way e.g. Android Market installs / uninstalls packages. They use a richer version of the PackageManager. This can bee seen by downloading the Android source code from the Android Git repository. Below are the two hidden methods that corresponds to the Intent approach. Unfortunately they are not available to external developers. But perhaps they will be in the future?
The better approach
Installing APK using the PackageManager
/**
* #hide
*
* Install a package. Since this may take a little while, the result will
* be posted back to the given observer. An installation will fail if the calling context
* lacks the {#link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
* package named in the package file's manifest is already installed, or if there's no space
* available on the device.
*
* #param packageURI The location of the package file to install. This can be a 'file:' or a
* 'content:' URI.
* #param observer An observer callback to get notified when the package installation is
* complete. {#link IPackageInstallObserver#packageInstalled(String, int)} will be
* called when that happens. observer may be null to indicate that no callback is desired.
* #param flags - possible values: {#link #INSTALL_FORWARD_LOCK},
* {#link #INSTALL_REPLACE_EXISTING}, {#link #INSTALL_ALLOW_TEST}.
* #param installerPackageName Optional package name of the application that is performing the
* installation. This identifies which market the package came from.
*/
public abstract void installPackage(
Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName);
Uninstalling APK using the PackageManager
/**
* Attempts to delete a package. Since this may take a little while, the result will
* be posted back to the given observer. A deletion will fail if the calling context
* lacks the {#link android.Manifest.permission#DELETE_PACKAGES} permission, if the
* named package cannot be found, or if the named package is a "system package".
* (TODO: include pointer to documentation on "system packages")
*
* #param packageName The name of the package to delete
* #param observer An observer callback to get notified when the package deletion is
* complete. {#link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
* called when that happens. observer may be null to indicate that no callback is desired.
* #param flags - possible values: {#link #DONT_DELETE_DATA}
*
* #hide
*/
public abstract void deletePackage(
String packageName, IPackageDeleteObserver observer, int flags);
Differences
When using intents the local package manager is not made aware of which application the installation originated from. Specifically, getInstallerPackageName(...) returns null.
The hidden method installPackage(...) takes the installer package name as a parameter, and is most likely capable of setting this value.
Question
Is it possible to specify package installer name using intents?
(Maybe the name of the installer package can be added as an extra to the installation intent?)
Tip: If you want to download the Android source code you can follow the steps described here: Downloading the Source Tree. To extract the *.java files and put them in folders according to the package hierarchy you can check out this neat script: View Android Source Code in Eclipse.
Android P+ requires this permission in AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
Then:
Intent intent = new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:com.example.mypackage"));
startActivity(intent);
to uninstall. Seems easier...
This is not currently available to third party applications. Note that even using reflection or other tricks to access installPackage() will not help, because only system applications can use it. (This is because it is the low-level install mechanism, after the permissions have been approved by the user, so it is not safe for regular applications to have access to.)
Also the installPackage() function arguments have often changed between platform releases, so anything you do trying access it will fail on various other versions of the platform.
EDIT:
Also it is worth pointing out that this installerPackage was only added fairly recently to the platform (2.2?) and was originally not actually used for tracking who installed the app -- it is used by the platform to determine who to launch when reporting bugs with the app, for implementing Android Feedback. (This was also one of the times the API method arguments changed.) For at least a long while after it was introduced, Market still didn't use it to track the apps it has installed (and it may very well still not use it), but instead just used this to set the Android Feedback app (which was separate from Market) as the "owner" to take care of feedback.
API level 14 introduced two new actions: ACTION_INSTALL_PACKAGE and ACTION_UNINSTALL_PACKAGE. Those actions allow you to pass EXTRA_RETURN_RESULT boolean extra to get an (un)installation result notification.
Example code for invoking the uninstall dialog:
String app_pkg_name = "com.example.app";
int UNINSTALL_REQUEST_CODE = 1;
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.parse("package:" + app_pkg_name));
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
startActivityForResult(intent, UNINSTALL_REQUEST_CODE);
And receive the notification in your Activity#onActivityResult method:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == UNINSTALL_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Log.d("TAG", "onActivityResult: user accepted the (un)install");
} else if (resultCode == RESULT_CANCELED) {
Log.d("TAG", "onActivityResult: user canceled the (un)install");
} else if (resultCode == RESULT_FIRST_USER) {
Log.d("TAG", "onActivityResult: failed to (un)install");
}
}
}
If you have Device Owner (or profile owner, I haven't tried) permission you can silently install/uninstall packages using device owner API.
for uninstalling:
public boolean uninstallPackage(Context context, String packageName) {
ComponentName name = new ComponentName(MyAppName, MyDeviceAdminReceiver.class.getCanonicalName());
PackageManager packageManger = context.getPackageManager();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
PackageInstaller packageInstaller = packageManger.getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
int sessionId = 0;
try {
sessionId = packageInstaller.createSession(params);
} catch (IOException e) {
e.printStackTrace();
return false;
}
packageInstaller.uninstall(packageName, PendingIntent.getBroadcast(context, sessionId,
new Intent("android.intent.action.MAIN"), 0).getIntentSender());
return true;
}
System.err.println("old sdk");
return false;
}
and to install package:
public boolean installPackage(Context context,
String packageName, String packagePath) {
ComponentName name = new ComponentName(MyAppName, MyDeviceAdminReceiver.class.getCanonicalName());
PackageManager packageManger = context.getPackageManager();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
PackageInstaller packageInstaller = packageManger.getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
try {
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
OutputStream out = session.openWrite(packageName + ".apk", 0, -1);
readTo(packagePath, out); //read the apk content and write it to out
session.fsync(out);
out.close();
System.out.println("installing...");
session.commit(PendingIntent.getBroadcast(context, sessionId,
new Intent("android.intent.action.MAIN"), 0).getIntentSender());
System.out.println("install request sent");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
System.err.println("old sdk");
return false;
}
The only way to access those methods is through reflection. You can get a handle on a PackageManager object by calling getApplicationContext().getPackageManager() and using reflection access these methods. Checkout this tutorial.
According to Froyo source code, the Intent.EXTRA_INSTALLER_PACKAGE_NAME extra key is queried for the installer package name in the PackageInstallerActivity.
On a rooted device, you might use:
String pkg = context.getPackageName();
String shellCmd = "rm -r /data/app/" + pkg + "*.apk\n"
+ "rm -r /data/data/" + pkg + "\n"
// TODO remove data on the sd card
+ "sync\n"
+ "reboot\n";
Util.sudo(shellCmd);
Util.sudo() is defined here.
If you are passing package name as parameter to any of your user defined function then use the below code :
Intent intent=new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:"+packageName));
startActivity(intent);
If you're using Kotlin, API 14+, and just wish to show uninstall dialog for your app:
startActivity(Intent(Intent.ACTION_UNINSTALL_PACKAGE).apply {
data = Uri.parse("package:$packageName")
})
You can change packageName to any other package name if you want to prompt the user to uninstall another app on the device
Prerequisite:
Your APK needs to be signed by system as correctly pointed out earlier. One way to achieve that is building the AOSP image yourself and adding the source code into the build.
Code:
Once installed as a system app, you can use the package manager methods to install and uninstall an APK as following:
Install:
public boolean install(final String apkPath, final Context context) {
Log.d(TAG, "Installing apk at " + apkPath);
try {
final Uri apkUri = Uri.fromFile(new File(apkPath));
final String installerPackageName = "MyInstaller";
context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
Uninstall:
public boolean uninstall(final String packageName, final Context context) {
Log.d(TAG, "Uninstalling package " + packageName);
try {
context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
To have a callback once your APK is installed/uninstalled you can use this:
/**
* Callback after a package was installed be it success or failure.
*/
private class InstallObserver implements IPackageInstallObserver {
#Override
public void packageInstalled(String packageName, int returnCode) throws RemoteException {
if (packageName != null) {
Log.d(TAG, "Successfully installed package " + packageName);
callback.onAppInstalled(true, packageName);
} else {
Log.e(TAG, "Failed to install package.");
callback.onAppInstalled(false, null);
}
}
#Override
public IBinder asBinder() {
return null;
}
}
/**
* Callback after a package was deleted be it success or failure.
*/
private class DeleteObserver implements IPackageDeleteObserver {
#Override
public void packageDeleted(String packageName, int returnCode) throws RemoteException {
if (packageName != null) {
Log.d(TAG, "Successfully uninstalled package " + packageName);
callback.onAppUninstalled(true, packageName);
} else {
Log.e(TAG, "Failed to uninstall package.");
callback.onAppUninstalled(false, null);
}
}
#Override
public IBinder asBinder() {
return null;
}
}
/**
* Callback to give the flow back to the calling class.
*/
public interface InstallerCallback {
void onAppInstalled(final boolean success, final String packageName);
void onAppUninstalled(final boolean success, final String packageName);
}

Get Android Google Analytics referrer tag

We're planning to use Google Analytics to track ad click-through referrals, through the Android Market, to our application.
According to the Google Documentation the referrer tag comes through via an intent, and is automatically recorded by the Google Analytics library.
That's great, but we need to extract that referral tag for our own internal analytics. The documentation is shy on details about how to grab it out of the initial launch intent, and instructions on how to simulate this before going live.
Does anyone have experience with this?
I went ahead and published a dead pixel finder app to play with snooping on the intent. For some reason, when I registered two different broadcast receivers (ie com.google.android.apps.analytics.AnalyticsReceiver and my own), I never received it on my own.
So instead, I registered only my own receiver, process the information, and pass it along to Google Analytics. Don't know how kosher this is, but it works. Code follows.
public class ZSGoogleInterceptor extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String referrerString = extras.getString("referrer");
// Next line uses my helper function to parse a query (eg "a=b&c=d") into key-value pairs
HashMap<String, String> getParams = Utility.getHashMapFromQuery(referrerString);
String source = getParams.get("utm_campaign");
if (source != null) {
SharedPreferences preferences = context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
Editor preferencesEditor = preferences.edit();
preferencesEditor.putString("ga_campaign", source);
preferencesEditor.commit();
}
// Pass along to google
AnalyticsReceiver receiver = new AnalyticsReceiver();
receiver.onReceive(context, intent);
}
}
Then, when your application is actually launched, you can pull the value back out of the shared preferences and pass it along with user signup or whatever. I used the campaign tag for my purposes, but you can grab any parameters you want out of the referrer string created with this tool.
#DougW 's answer updated for Analytics SDK 4
https://developers.google.com/analytics/devguides/collection/android/v4/campaigns
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.analytics.CampaignTrackingReceiver;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Created by dave on 15-05-05.
*/
public class ReferrerReceiver extends BroadcastReceiver {
public static final String REFERRER = "REF";
public static final String UTM_CAMPAIGN = "utm_campaign";
public static final String UTM_SOURCE = "utm_source";
public static final String UTM_MEDIUM = "utm_medium";
public static final String UTM_TERM = "utm_term";
public static final String UTM_CONTENT = "utm_content";
private final String[] sources = {
UTM_CAMPAIGN, UTM_SOURCE, UTM_MEDIUM, UTM_TERM, UTM_CONTENT
};
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String referrerString = extras.getString("referrer");
try {
Map<String, String> getParams = getHashMapFromQuery(referrerString);
SharedPreferences preferences = context
.getSharedPreferences(REFERRER, Context.MODE_PRIVATE);
SharedPreferences.Editor preferencesEditor = preferences.edit();
for (String sourceType : sources) {
String source = getParams.get(sourceType);
if (source != null) {
preferencesEditor.putString(sourceType, source);
}
}
preferencesEditor.commit();
} catch (UnsupportedEncodingException e) {
Log.e("Referrer Error", e.getMessage());
} finally {
// Pass along to google
CampaignTrackingReceiver receiver = new CampaignTrackingReceiver();
receiver.onReceive(context, intent);
}
}
public static Map<String, String> getHashMapFromQuery(String query)
throws UnsupportedEncodingException {
Map<String, String> query_pairs = new LinkedHashMap<String, String>();
String[] pairs = query.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"),
URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
}
return query_pairs;
}
}
In you manifest file:
<service android:name="com.google.android.gms.analytics.CampaignTrackingService" />
<receiver android:name="com.google.android.gms.analytics.CampaignTrackingReceiver" />
<!-- Make sure this points to the location of Referrer Receiver in your package -->
<receiver android:name=".ReferrerReceiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
Check at:
Get referrer after installing app from Android Market
for the solutions.
Tobia

Categories

Resources