I have done an small App in Android, which I want to set as trial version for 2 days, after 2 days it should ask for a key. If the user uninstalls the App after expire date, he shouldn't be able to use the App without a key...
An idea could be release two versions of the app. One free version with some limitations or Ad's in it and another paid version of the app.
You need to setup a database which will be online assign a specific id to each device. If you are going to save the date of install in the SharedPreference or any local memory, the user can just remove it from his phone by simple clearing all the application data. He wouldn't have to uninstall it even.
So, every time a new user installs your application, you need to store the date of install corresponding to each device in your online database. Everytime the application is started, you need to ask the server for the date of install corresponding to that device and let the user proceed iff it is in the trial period, otherwise ask him for the key there.
I don't know, how safe/secure it would be, but you could use SharedPreferences to store this data. Just a really small example:
On startup:
SharedPreferences prefs = getSharedPreferences("AppName", Context.MODE_PRIVATE);
boolean firstRun = prefs.getBoolean("first_run", true);
long currentTime = System.currentTimeMillis();
if(firstRun)
{
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("first_run", false);
editor.putLong("first_run_time", currentTime);
editor.commit();
}
else
{
long firstRunTime = prefs.getLong("first_run_time", 0);
long twoDays = 2 * 24 * 60 * 60 * 60 * 1000;
if(currentTime - firstRunTime > twoDays)
{
//Expired
}
else
{
//Not yet expired
}
}
Please note, that if the user uninstalls the app, and then reinstalls it, or simply deletes the applications stored data, the "timer" will reset!
A safer method would be to store this data in an online database, but thats more complicated to solve, and it would require internet connection all the time to check if the app is expired.
Just use Android Licencing. It's pretty straight forward and awesome.
Anything more secure than that would be so much trouble. I don't think it's worth the effort for most apps.
http://developer.android.com/google/play/licensing/index.html
Related
I recently started learning Android to port my iOS app to Android.
User registration in my app is optional, hence the user can decide to get started right away without any delay. However I still need a form of identification against fraud and if the user has passed the first week of free trial. Otherwise the user can just keep deleting and reinstalling the app to use it for free, forever.
On iOS I have solved the problem through the keychain. Any values stored in there remain there even after the app has been uninstalled.
import KeychainAccess
let keychain = Keychain(service: Constants.keychainServiceID).synchronizable(false).accessibility(.alwaysThisDeviceOnly).accessibility(.alwaysThisDeviceOnly)
let deviceId = UUID().uuidString.lowercased()
keychain["DEVICE_ID"] = deviceId
I don't seem to find anything like that on Android.
A unique Device ID doesn't seem to be available either based on this answer
Hence is there a way to achieve this or do I have to make user registration mandatory?
UPDATE:
In iOS when a keyChain value is set, the user can't ever update or delete it. Even after the app is uninstalled. During unit testing I can delete the keychain entry like this:
let keychain = Keychain(service: Constants.keychainServiceID).synchronizable(false).accessibility(.alwaysThisDeviceOnly)
do {
try keychain.remove("DEVICE_ID")
} catch let error {
print("error: \(error)")
}
Can I do that in Android?
More easily you can do like this, this is a wrapper on shared preference.
https://github.com/kishandonga/EasyPrefs
public static void setUniqueId(){
if(!Prefs.read().content("is_unique_id_set", false)){
String id = UUID.randomUUID().toString();
Prefs.write().content("unique_id", id)
.content("is_unique_id_set", true)
.commit();
}
}
public static String getUniqueId(){
return Prefs.read().content("unique_id", "");
}
Cases when unique id changed
App uninstalled and then reinstalled
Clear cache or reset
I've recently discovered that Firebase Auth saves itself on the device even after my app is uninstalled. I can't figure out how to REMOVE this old Auth info.
I don't want a user to still be signed in after uninstalling and reinstalling the app. If for no other reason than my own testing of what I expect to be "clean installs" on the same device.
I understand there is no easy way to capture an uninstall event, so I want to clear out any potential old Auth info on the first launch.
So I added code (which seems to work fine) to check if this is the first launch:
Boolean firstRun = prefs.getBoolean("firstrun", true);
if (firstRun) {
// delete everything an old user could have left behind
// ==> This is where I need help <==
prefs.edit().putBoolean("firstrun", false).apply();
} else {
// move along, not the first launch
}
I've tried (unsuccessfully):
FirebaseAuth authData = FirebaseAuth.getInstance();
authData.signOut();
These calls also seem to be the advice in this related question for iOS, but I haven't been able to apply its wisdom:
Firebase - Deleting and reinstalling app does not un-authenticate a user
Even after calling signOut() the app keeps logging me in under the old account!
My "logout" button uses FirebaseAuth.getInstance().signOut(); and works. Is there something odd (possessed?) about this "old" Auth instance that is being saved after an uninstall that it just won't die?
Specifically when I uninstall and then install/run from Android Studio:
at first authData and currentUser both are not null
I call the above code, trying to get rid of this old user
3 millisecond later (immediately after I call that
code) they are still NOT NULL.
Another 2 milliseconds, currentUser IS NULL (yay?)
Another 71 milliseconds... still null (so far so good)
Just under a second later... I'M SIGNED IN AS THE OLD USER?! How is this possible?
In the Firebase Console under Authentication, this account is shown as last signed in 6 days ago. So it's not somehow getting re-signed-in.
Does anyone know how to remove FirebaseAuth data from a device? I don't want to "delete" the user account, just remove all traces of it from this device.
Oddly enough, the account I keep getting unwillfully logged in under isn't even the last account that logged into my app on this device. And this was never a problem in the past (hence my not even knowing that Firebase saved Auth after uninstall). So it looks like Auth info isn't always saved after uninstall... but when it happens it's impossible to remove?
Any help much appreciated!
Add android:allowBackup="false" in your <application> in manifest:
From the docs:
android:allowBackup
Whether to allow the application to participate in the backup and restore infrastructure. If this attribute is set to false, no backup or restore of the application will ever be performed, even by a full-system backup that would otherwise cause all application data to be saved via adb. The default value of this attribute is true.
Try also FirebaseAuth.getInstance().getCurrentUser().delete
Firebase stores auth info in shared preference with file names starting with "com.google.firebase.auth.api.". Therefor if you delete these files as part of your log off flow it would help the purpose.
public void clearFirebaseAuthInfo(Context ctx)
{
File dir = new File(ctx.getFilesDir().getParent() + "/shared_prefs/");
String[] children = dir.list();
for (int i = 0; i < children.length; i++)
{
if(children[i].contains("com.google.firebase.auth.api."))
{
new File(dir, children[i]).delete();
}
}
}
I have a SharedPreference that counts the amount of launches of my App. I expect this to be 0, when I install my app. Nevertheless it is 14. The same strange behaviour I observe with my database, that already exists on a fresh install.
I didn't intent to recycle my app data (like in the Google Cloud). On my device in the account settings the app-data sync is on. If I turn it off, and make a reinstall I observe the same behaviour.
Anyone has every observed such a behaviour? Is there any way to prevent recycling old data and force a proper install?
In Android Marshmallow Google introduced the "Auto Backup" feature which is turned on by default if your targetSdkVersion is >=23.
This will back up your database and SharedPreferences by default and restore it when you re-install the application. To turn this feature off you have to add android:allowBackup="false" to your AndroidManifest.xml.
More info here: Auto Backup for Apps
Review your code in AndroidManifest on tag application if it has android:allowBackup="false". If you don't have (by default it's true), your app participates on android backup and restore infrastructure and can happen exactly what you say.
More information in this post: What is "android:allowBackup"?
This needs to be handled from app side regarding shared Prefs.
Created a shared preference helper class and in the helper class have the below condition.
private static String SHARED_PREFS_VERSION = "SharedPrefsVersion"; // In this save the version of current shared Prefs.
void SharedPrefsHelper() {
if( BuildConfig.Version > getSharedPrefsVersion() ) {
SharedPreferences.Editor editor = prefs.edit(); editor.clear(); // Clear all the shared Prefs and update the current version.
SetSharedPrefsVersion(BuildConfig.Version);
}
}
For further reference look at :
https://stackoverflow.com/a/12381061/7364024
I have the following code to track when an app is launched for the first time on a device,
however it doesn't match the data I am getting from Google Analytics in the New Users category. Can anyone see anything in the code that could be unreliable? For example, today I see 3 installs from this code, but I have 5 new users who could only download this app from Google Play.
String INSTALL_SOURCE = "Google Play";
TelephonyManager tm;
tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
String INSTALL_COUNTRY = tm.getSimCountryIso();
prefs = getSharedPreferences("user_stats", MODE_PRIVATE);
boolean firstTime = prefs.getBoolean("isFirstTime", true);
if (firstTime) {
rentracker.trackEvent("Install Source", INSTALL_SOURCE, INSTALL_COUNTRY, 1);
Editor editor = prefs.edit();
editor.putBoolean("isFirstTime", false);
editor.commit();
}
Log.d(TAG, "Is this the first time?: " + firstTime);
String android_id = Secure.getString(this.getContentResolver(),
Secure.ANDROID_ID);
rentracker.trackEvent("App Startup - " + INSTALL_SOURCE, INSTALL_COUNTRY, "ID: " + android_id,1);
Can anyone see anything in the code that could be unreliable?
As one commenter suggested, just because this code exists does not mean that it actually has run, as the user may not have launched your activity yet. If you think that this code will somehow automatically run without the user's involvement, that is probably not the case on Android 3.1 and higher.
Presumably, rentracker is supposed to be communicating over the Internet, but not everyone has continuous Internet access. Hence, it may be that your code has run, but your back end has not found out about that yet, because the user was not online at the time.
You are assuming that the Play Store Developer Console reports downloads accurately and in a timely fashion. The Play Store Developer Console has not been the most reliable piece of software in human history, and so it is entirely possible that your comparison data is flawed.
My app download 5 files .apk from internet and after each file of 5 install successful first time, I want to send device id to the server.
so is there way to check apps installed success the first time
You can get first installation time using
Date app_install_date = null;
long installation_date = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0).firstInstallTime;
app_install_date = new Date(installation_date);
I think you can compare that to current time and do what you require.
you can track your app usage and other statistics through Google Analytics.You can also send any data like device id through Google Analytics to Google Analytics Site.