After some research I found that Android likes to cache some parts of an app while installing to improve the performance while runtime.
Is there a way to prevent Android from caching things from my app?
I am sharing my app via my website and users install and update the app manually. As soon as I update my app some Activities and Code-parts seems to be cached on their devices.
You could delete your cache everytime before you update or before you close you application.
Code to clear the cache:
public static void trimCache(Context context) {
try {
File dir = context.getCacheDir();
if (dir != null && dir.isDirectory()) {
deleteDir(dir);
}
} catch (Exception e) {
// TODO: handle exception
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// The directory is now empty so delete it
return dir.delete();
}
Call Trimcache when you want to clear the cache (before you update perhaps? or override the onStop() method, to clear the cache when the application is going to close.
The way I see you should also have a cache problem when you're NOT updating your app.
If you want to force a server fetch when you upgrade your app you could store a boolean in Shared Preferences, using a key associated with the app version. So when you install version 1 you fetch and make putsBoolean(version, true) where version == "1". When version 2 is installed you'll find a false, which will trigger a fetch, followed by setting putsBoolean(version, true) - but in this case version == "2".
If you are reusing information that have a different meaning when you update, the solution is storing the information in a different part of the cache, so it's not sent to an activity that is not prepared to display it.
Otherwise the solution by #jordy-dieltjens seems a good one.
Related
I am resolving some security defects for my app.
Defect is:
Should not allow release app to be run in emulator
Release app should not be debuggable
Should not connect to debugger
Release app should be installed from play store not from other resource
And app signature verification
Code 1)
private static boolean isEmulator() {
try {
boolean goldfish = getSystemProperty("ro.hardware").contains("goldfish");
boolean emu = getSystemProperty("ro.kernel.qemu").length() > 0;
boolean sdk = getSystemProperty("ro.product.model").equals("sdk");
if (emu || goldfish || sdk) {
return true;
}
} catch (Exception e) {
}
return false;
}
Code 2)
public static boolean isDebuggable(Context context) {
if (IdscProperties.getIsDebug()) {
return true;
}
if (isDebuggableEnabled(context) || detectDebugger() || detectThreadCpuTimeNanos()) {
return true;
}
return false;
}
private static boolean isDebuggableEnabled(Context context) {
return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}
Code 3)
private static boolean detectDebugger() {
return Debug.isDebuggerConnected();
}
Code 4)
private static boolean isInstallerPlayStore(Context context) {
final String installer = context.getPackageManager().getInstallerPackageName(context.getPackageName());
return installer != null && installer.startsWith(PLAY_STORE_APP_ID);
}
Code 5)
private static boolean isAppSignatureMatches(Context context) {
String signature = PackageVerifier.getCertificateHash(context, context.getPackageName());
return SIGNATURE.equals(signature);
}
So, My aim is to not allow these checks in debug builds.
We shall create a flag in some prob file and read it when these checks happen and disallow the function execution.
But the flag shall be modified by the hacker and re-pack the APK to dis-allow these checks.
My expectation is allow these checks in release build and not in debug build without any modifiable flag checks.
Before you start on this path, I want to make sure that you realize 2 things:
Every precaution you implement can be (relatively easily) circumvented on a rooted device
Your app can be easily decompiled into bytecode offline, and any security-related code will be plainly visible.
So, knowing this, if your aim is to prevent piracy, you also need to realize that anything you do will only add some extra steps for the attacker to go through. But if someone really wants to do it, it will not stop them.
If you still want advice on how to implement this, let me know
How can I delete pictures saved in External Storage Public Directory Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) when uninstall the app.
You should save your data in External Cache bqz you cannot delete any file after uninstall. External cache will be deleted with your app. selectAvailableCacheDir will provide you file object of available cache.
static File selectAvailableCacheDir(Context context) {
for (File file : ContextCompat.getExternalCacheDirs(context)) {
if (file != null && ensureDirExists(file))
return file;
}
return null;
}
static Boolean ensureDirExists(File dirFile) {
if (!dirFile.exists()) {
return dirFile.mkdir() || dirFile.mkdirs();
} else if (dirFile.exists() && dirFile.isDirectory())
return true;
return false;
}
I don't know what you want to achieve actually.
But When an application is uninstalled, all of its components are uninstalled (this includes any services, content providers, etc.). The system broadcast ACTION_PACKAGE_REMOVED is made after the application has been removed, so there is no way that this application can get it.
Adding to #SRB bans answer,
You can do that by using a Broadcast Receiver.
Hope it helps.
I have a crash for which I receive the following report in Google Play.
java.lang.OutOfMemoryError: [memory exhausted]
at dalvik.system.NativeStart.main(Native Method)
As you can see, not a lot of information. There is this question that asks the same thing but I don't believe the answer of ignoring it is acceptable.
The fact there is nothing about my application in the stack trace suggests that it's the OS that's not allowing the application to start. This implies there isn't much we can do however, even after users have rebooted their devices, they still cannot open the application. My application isn't big: 22.20MB on the device.
Please see the following or the crash report stats.
Is there anything I can do to rectify this or at least minimise the chances of this happening?
Don't know if its a right solution or not but it solved my issue. The common reason of java.lang.OutOfMemoryError is overflowing the limit of cache. What I did, I have cleared the Application cache on the launcher activity. So whenever the application is launched at first it clears the cache.
add this methods out side of the onCreate method of your launcher activity.
//Following two methods are used to clear the Cache memory of this application
public static void deleteCache(Context context) {
try {
File dir = context.getCacheDir();
if (dir != null && dir.isDirectory()) {
deleteDir(dir);
}
} catch (Exception e) {}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
And call deleteCache(this); inside of the onCreate.
I am using the Android Billing API V3 for querying purchase information from the play store. I am wondering if it is possible to clear the local cache.
V3 added the local caching feature for the billing API to cut down on network traffic. I have an update service which is run daily which updates my metadata and since I display the costs in my application I wish to flush the local cache and trigger an update in case I have updated prices to ensure the correct price is shown.
Documentation says:
Because the Google Play client now caches In-app Billing information locally on the device, you can use the Version 3 API to query for this information more frequently, for example through a getPurchases call. Unlike with previous versions of the API, many Version 3 API calls will be serviced through cache lookups instead of through a network connection to Google Play, which significantly speeds up the API's response time.
You must know that the android in app purchase one time purchases are allow only one time in the lifetime for one user. you want it again you have to make a request or create a new product in play console. for more go to this link.
https://developer.android.com/google/play/billing/billing_onetime
Unfortunately not, the Google Play client is app doing the caching, and there is not an API exposed to clear the cache.
I don't see why you want to clear the cache though? The Google Play client is notified of any changes, so would invalidate it's cache accordingly. Just assume the calls returned are correct.
Try this :
Add this Application class :
package com.hrupin.cleaner;
import java.io.File;
import android.app.Application;
import android.util.Log;
public class MyApplication extends Application {
private static MyApplication instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static MyApplication getInstance() {
return instance;
}
public void clearApplicationData() {
File cache = getCacheDir();
File appDir = new File(cache.getParent());
if (appDir.exists()) {
String[] children = appDir.list();
for (String s : children) {
if (!s.equals("lib")) {
deleteDir(new File(appDir, s));
Log.i("TAG", "**************** File /data/data/APP_PACKAGE/" + s + " DELETED *******************");
}
}
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
}
Then, Make this call from any Activity:
MyApplication.getInstance().clearApplicationData();
Reference :
How to Clear User Data in your Android Application programmatically
Thanks.
Requirement
Scan all folders and files on external storage to find all apk files and for each apk file, get info and display progress.
How I did it so far
My initial thought is that this is a simple thing to achieve. But well... even it it sort of works, it does not perform as expected.
I use an AsyncTask to perform the scanning in background. Here is how I do:
private ArrayList<String> sdcardAppsPath;
protected class ScanTask extends AsyncTask<Context, Scanner, ArrayList<Apk>> {
private ArrayList<Apk> sdcardApps;
#Override
protected ArrayList<App> doInBackground(Context... params) {
visitAllDirsAndFiles(Environment.getExternalStorageDirectory());
for (String path : sdcardAppsPath) {
//get info about apk file and
publishProgress(values) //show in some textviews number of files scanned, total files
sdcardApps.add(currentScannedItemFoundInfo);
}
return sdcardApps
}
#Override
protected void onProgressUpdate(Scanner... values) {
super.onProgressUpdate(values);
// update some textView texts based on values
}
}
And
// Process all files and directories under dir
public void visitAllDirsAndFiles(File dir) {
if (dir != null) {
if (dir.getAbsoluteFile().toString().endsWith(".apk")) {
sdcardAppsPath.add(dir.getAbsoluteFile().toString());
}
if (dir.isDirectory()) {
String[] children = dir.list();
if (children != null) {
for (int i = 0; i < children.length; i++) {
visitAllDirsAndFiles(new File(dir, children[i]));
}
}
}
}
}
As you can see after vistitAllDirsAndFiles I get an ArrayList<String> with all apk files I need, so I can check for each what I want. The downside is that it might take a lot of time to build this sdcardAppsPath if there are many files on the card and the app shows no progress while the paths are being found.
What I want to achieve
I want to be able in the doInBackground to somehow for each found file, get the info I need, update progress and then continue with scanning. Any ideas how to update my code to work like this ?
I would think that you would want to call publishProgress inside your visitAllDirsAndFiles method if you want to update progress while searching for files, instead of iterating through the list afterwards and calling it then...