In one of my App, I would like to give a feature as a trial for only 20 attempts. Once the user wants to access the feature for the 21st attempt, he/she will be prompted for in-App purchase.
My question is how can I make this variable persistent so that even if the user uninstalls the app and re-installs, the counter does not reset and takes the last value before the uninstall.
Please help.
The easiest way is to use Backup API and backup your data online. It is very easy to use and here is tutorial:
http://developer.android.com/training/cloudsync/backupapi.html
The disadvantage of this method is that user can disable backups in phone's settings.
Another method requires you to send data to server. I would suggest to use parse.com since it does not require you to write any server code, they have very easy-to-use library for Android and their free plan is very generous. Here is a little tutorial:
https://parse.com/tutorials/get-started-with-android
You can send some sort of unique id (device or account specific) and counter to the cloud every time user triggers your trial feature. Also you can query your counter from the cloud when application launches the first time.
To create that unique id you can approach with few methods:
Try to obtain 64-bit unique number, which is generated when device first boots:
String androidID = Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID);
Note that it was reported that for some device this value might be null. You can verify your androidID variable and if it is null, you can try another method that will allow you to access user's primary e-mail (you probably want to hash it prior to sending it your server).
Also make sure to add android.permission.GET_ACCOUNTS permissions to your manifest file:
final Account[] accounts = AccountManager.get(context).getAccounts();
for (final Account account : accounts) {
if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
final String email = account.name;
// hash email and use it
}
}
if email cannot be obtained - you might also want to try to get device id from telephony manager:
// For CDMA phone getDeviceId() is equal to value request for Secure.ANDROID_ID
final TelephonyManager telMgr = (TelephonyManager)getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
final String deviceId = telMgr.getDeviceId();
(don't forget to add android.permission.READ_PHONE_STATE permission to your manifest)
Hope that it gave you enough information to add trial functionality into your code.
Also if your in-app purchase is actually a subscription, then Google already implemented trial functionality for you:
http://developer.android.com/google/play/billing/billing_subscriptions.html
(search for free trial)
You have no way of maintaining anything locally for the user if they uninstall or reinstall the application.
If you need the uninstall/re-install requirement, this is counter that will need to be logged on your back-end rather than on the device. You can do this by storing the device's id on your server and incrementing your ticker when appropriate.
I simply define a serializable Expiration object that I store to SD with a dot in front of it to make it hidden.
The object contains time of creation and other metadata.
When the app starts, it checks whether Expiration exists, if not it is create. This way I always know the exact time when the app was installed, despite uninstall/reinstalls.
The downside to this method is that it requires some sort of external storage as we want to go outside of the standard app folder of the internal storage, which is wiped upon uninstall.
To circumvent this, you could look for some way of getting/giving a device a unique id, that remains the same after reinstall, and upload the data to a server. This has the benefit that the user cannot reset the expiration by wiping the SD either.
Related
I'm developing an android app which contains registration form also,
Here I want to make user can register only once in the device. and if register again (by clearing data or reinstall) with different mobile number and email id, app should give error message.
I think you need to check IMEI number of device
IMEI number will not be changed if sim card changed.
This alone cannot be achieved on mobile device itself. You also need to maintain server which keep the identity of device and user mobile number together. device identity can be combination of IMEI and device id
When you try to register, you do all local validation on client but ultimately 1 network call is must to register, for this send device_id and newly registered number.
Next time when some user tries to register with new number from same device, u'd already have this information on server, server can respond back telling, hey looks like this mobile device is already associated with an number do you wish to use the previous number instead.
In case, user denies, he must be allowed to delete the old relation between oldnumber-current device.
There after he can proceed with the way initially he started to register.
Also this is completely business requirement, whether u want to have 1device-> #numbers or #numbers -> 1device. But i would rather suggest to keep it safe simple and secure with 1device->1number.
For Android Version 6 And Above, WLAN MAC Address has been deprecated.
For uniquely Identification of devices, You can Use Secure.ANDROID_ID.
And we don't need any additional permission to retrieve Android ID.
you can get Android Id like:
public String getDeviceUniqueID(Activity activity){
String device_unique_id = Secure.getString(activity.getContentResolver(),
Secure.ANDROID_ID);
return device_unique_id;
}
You can do this by below approach.
On sign up, get user device IMEI number as well and store on server database as well.(In this step make sure that user that IMEI number does not exist)
I've read quite a few questions here but none really answered my question.
I know that the best place to store the key is serverside, but my app does not have a server. Also, asking for password each time the user starts the app is not an option either.
From what I've read, there are 2 places to actually store the data:
SharedPreference but encrypt it: this means that a user with root can get access to xml file easy and if decompile apk can get to the actual value
in a sqlite database but is really just a matter of using a sqlite db browser to read the data.
Basically I want to store 2 things:
a token which can be reset by the user anytime by logging into a web browser
the in app purchases purchased by the user.
For in app purchases I can fix this pretty simple: query on each app start the purchased items. This means that even if the app stores in SharedPreferences the values, for cases when querying fails, I still override this values if not the case.
One thing is decided: do not store them in plain text but encrpt it.
As for encryption, I was thinking of using some sort of unique id for each app installation as key for AES. Because here's the thing, for instance if I encrypt an in app purchase value with same hardcoded key on all devices, a SharedPreference value from a purchased device can be copied on a rooted device and get access to the app without paying. I want to avoid this, and by using maybe Settings.Secure.ANDROID_ID can I simply encrypt something that would not be the same on any other device and more important, not even the developer has access to decryption. What key can I use that is device dependent and would allow encryption particular for that device. That means copying a backup to another device, would not work, because decryption would return different results.
I know that there are many questions on this and probably my question will be downvoted, but many android versions have changed since that questions.
The basics remain: how can I most securely store some values related to my android app?
Use Imei for unique device ID
from
public static String getDeviceIMEI(Context context) {
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager.getDeviceId() != null)
return telephonyManager.getDeviceId();
return "";
}
Settings.Secure #ANDROID_ID returns the Android ID as an unique for each user 64-bit hex string.
import android.provider.Settings.Secure;
private String android_id = Secure.getString(getContext().getContentResolver(),
Secure.ANDROID_ID);
I am planning on storing a unique identifier after a user logs in for the first time on an Android and Apple app. This will make sure that the user can only access data from one device if they try to login through another device as I will flag then as having access. I will save this unique identifier in the devices preferences and use it for requests to get this private data.
With that being said I know the preferences can be deleted or removed. This piece of data isnt needed long term and in emergencies we can reset the users account back as if they never got access yet like for a factory reset or deleted app.
My question is, are there any issues with this? These arent developers so somehow getting access to the user preferences to find that unique identifier and using it elsewhere shouldnt be an issue.
for IOS:
You shouldn't concern your self with that cause there is no need to store the identifiers to user prefs (and it is not a good practice).
You just use:
[[[UIDevice currentDevice] identifierForVendor] UUIDString];
It will return the same value as long as it is called from the same device and same vendor. This is explained in:
http://www.doubleencore.com/2013/04/unique-identifiers/
I have inherited an app which comes as a free version, and Pro monthly subscription is bought via in-app items. The Pro status (a simple string "pro_status") is saved inside the AccountManager (package android.accounts).
//AccountManager initiated
AccountManager mAccountManager = AccountManager.get(this);
//fetch accounts which correspond to our package name
Account[] accounts = mAccountManager.getAccountsByType(getString(R.string.account_type));
//save Pro status inside the AccountManager
mAccountManager.setUserData(mAccount, "is_pro", "" + info.isPro());
The app suffers from a strange bug that it forgets the Pro state randomly, either when you close the app or during the work.
Is this a good way to store Pro status? Could AccountManager be the reason why the app loses the idea of a Pro status?
I usually use either a database or SharedPreferences to store such data (besides storing it on the remote API), so I need a help from someone who used his app in the same way.
Usually the people playing with the setting "pro" status will be the one with rooted devices. Anyways the data stored in the account manager is visible to such users.
So, for such a use case, even account manager is not safe. Though other apps (with different UID) cannot access this data.
Also keep in mind that the user can delete the account from the settings which might be the reason for your settings going away.
My advice would be save this info in shared pref in encrypted form??
In all phones,there is a specific User Database which stores information regarding your accounts.
Is this a good way to store Pro status?
I cannot answer that however I can give you answer to related questions
Is it modifiable?
There are 2 ways of accessing this data, viz
The user explicitly gives permission to an application to read
account details for that particular account. This list of apps
which can access the details for this account are stored based on
PIDs,which cannot be same for different apps. check setUserData
and AUTHENTICATE_ACCOUNTS permission
This database can be accessed(and modified ) on a rooted device.
Can a user manually delete this data?
-Yes,He can delete the account from the device itself.It is his device and he can modify any account details on it too.
In my experiece,the Acccount Manager API is very temperamental, and prone to change which can break your code if it is not used in the way that it was intended to be i.e. store User Account details in centralised database.
You should look into the approach and comments(but not the answer) of this question
.
I agree with the shared preferences approach too.
I want to allocate unique ID to each user as soon as he installs the application so that whenever the app contacts the server I know who is contacting.
For this purpose, I thought that on first time installation, the app contacts the server and gets unique ID. But I don't know where to store it permanently so that next time when app is started, it knows what its ID is rather than contacting server.
Sorry if that is some obvious question as I am newbie.
This question has been asked many times on Stack Overflow.
In short: Android has always supported a unique ID. However, prior to Android 2.2, the ID was not always identical on certain kinds of phones. Since 2.2 is pretty ubiquitous by now, I would use that ID.
The Android Developer Blog has a good article about this.
And as Joachim said - you may want to consider a different approach altogether. Android's unique ID is good and persistent across factory resets, but not across a device upgrade. Also keep in mind that many people have several devices (like a phone and a tablet). You may want to use the Google account instead, the AccountManager can help you there.
Use SharedPreferences to store the unique id.
Here is an example:
Android SharedPreferences
For more complex data, you can use SQlite.
For unique id, you can use IMEI of device on which application is going to install. Refer this link for how to get IMEI number. Then stored that IMEI number in shared preference. Refer Guillermo lobar's link for that. You need to check for that unique id in preference when you application starts. At very first time, save that in preference. So when next time it checks for that id, app find it in preference and hence no need to connecting server. :)
You could get the IMEI of the device. As of API 26, getDeviceId() is deprecated. If you need to get the IMEI of the device, use the following:
String deviceId = "";
if (Build.VERSION.SDK_INT >= 26) {
deviceId = getSystemService(TelephonyManager.class).getImei();
}else{
deviceId = getSystemService(TelephonyManager.class).getDeviceId();
}