I found a problem with Shared Preferences which happens only for some devices and only with Android 9 (Pie) o above.
To encrypt my database I create a key and store it to my sharedPreferences.
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String content = sharedPreferences.getString(-nameOfTheKey-, "");
if (content == null || content.isEmpty()){
// Create and store the new key
content = restoreApplicationKey(context);
}
As you can see, first I check for the availability then I create if not exist or empty. This key isn't created in any other place. That is the only point.
When I try to first install the app on my device, the condition return false because the key-value is already present in my SharedPreferences. This is impossibile!
I found online that the solution is to set allowBackup="false" into the Manifest and reinstall the app but I don't understand this behavior. How is it possible that the kay-value is pre setted?
Also, before setting allowBackup to false, I noticed that if forcing the initialization and uninstall the app, after the reinstall the key is still present but the value is changed. Every time with the same string but different from the saved one. All others key are fine, except this one.
As I said, the above code is the only entry point and it's called only at the app launch. Also the restoreApplicationKey(context) is called only at this point.
Related
So my app is saving the names of Bluetooth devices the user has connected to previously in SharedPreferences which is than compared to all of the names of currently paired devices so on opening the app can instantly connect to the said device. This is done by this piece of code:
sharedPreferences = getApplicationContext().getSharedPreferences("BtNames", MODE_PRIVATE);
keys = sharedPreferences.getAll();
for(BluetoothDevice device : pairedDevices) {
try {
for (Map.Entry<String, ?> entry : keys.entrySet()) {...}
This loops through the paired devices and the entries of SharedPreferences whose value than is accessed by this code:
String device_name = device.getName();
String name = entry.getValue().toString();
Now both of these work well and entry.getValue()... returns the exact names of the previously connected devices. The problem occurs when trying to compare the two Strings by:
device_name.equals(name)
This returns false even though both of the Strings appear to be exact same when logged:
E/FaceTracker: EV3LO
E/FaceTracker: EV3LO
I have already tried to replace all spaces with nothing but that didn't work either. Maybe I overlooked something but at the moment I don't really have a clue what's going wrong.
Thanks in advance for answers.
The problem is a non printable and non ASCII character at the end or the beginning of the string. Please try the following script:
name.replaceAll("\\P{Print}","");
I hope it helpem and good luck if it didn't
I have a Native Android App in the Store. This App has its Settings stored in the SharedPreferences. Now I am working on an Update for the App. The Update is a Xamarin Cross-Platform App. App Name, Package Name, and those things are the same as in the Native App. But I can't get the values from SharedPreferences now. Did I make something wrong? I guess it's because of a different Application Context. But I don't know why.
Here is how the Native App is loading the Values:
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
final Set<String> keySet = prefs.getAll().keySet();
for (final String key : keySet) {
if (key.startsWith(DatabaseSetting.DATABASE_SETTING_KEY_PREFIX)) {
//Do stuff
}
}
After updating the App I can not see any keys in the prefs.
C# Xamarin Code to also load these prefs:
ISharedPreferences sharedPrefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
foreach (string key in sharedPrefs.All.Keys)
{
if(key.StartsWith(DATABASE_SETTING_KEY_PREFIX))
}
The App was updated without uninstalling the old one. Just deployed the new one.
Is it giving you a nullpoint?
Are you storing app context (Android.App.Application.Context) or class context(Context)?
Are there any other exceptions thrown that you possibly aren't catching?
I understand what SharedPreferences do but still struggling to get my head round what this piece of code is trying to do.
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
if (sharedPref.getBoolean("login", false)) {
edtUser.setText(sharedPref.getString("user", ""));
edtPass.setText(sharedPref.getString("pass", ""));
new SigninTask().execute("user=" + edtUser.getText(), "pass=" + edtPass.getText());
}
I understand that the first line is accessing the default SharedPreferences file. However I am still confused, what does this set code do exactly?. What information is it trying to get?. What does the last line do? (new SigninTask())..
sharedPref.getString("user", "") tries to get a preference with the key user from the SharedPreferences. If it's not found, it returns an empty String. This value is loaded to a Text control (I assume, since you didn't include the definition of edtUser).
The same is done with the value of pass, which probably represents a password.
Basically, this app probably stores in SharedPreferences the user and password that were entered by the user of the app in a previous launch of the app, so that the user doesn't have to enter them again every time the app is launched.
There should be additional code that would store the entered user and pass in the SharedPreferences, and store the login preference with the value true.
I have a blank-ish Android Project and what I want to do is take the user to a different "page/screen" if it is their first time only.
I know the logic for this but since I'm new to Android, I'm unsure of how to code this.
Below are the steps I believe I need to take in order to accomplish this:
App loads. If Local storage contains setting "FirstTimeUser", then it is not their first time using the app. Show the MainActivity page. If FirstTimeUser setting does not exist, it is their first time using the app (or they have uninstalled and reinstalled it), so instead, show WelcomeActivity page.
After viewing Welcome activity page, create FirstTimeUser setting and set to False.
But how do I code this for an Android app?
Use shared preferences as shown:
//declare as global
SharedPreferences prefs = null;
//and in your onCreate method:
prefs = getSharedPreferences("packageNameHere", MODE_PRIVATE);
if (prefs.getBoolean("firstrun", true)) {
//do stuff here if first run
//make sure to flag the boolean as false
prefs.edit().putBoolean("firstrun", false).commit();
}
else{
//if not first run, do something else
}
There is something called "SharedPreferences" that i believe your looking for.
http://developer.android.com/reference/android/content/SharedPreferences.Editor.html
I'd like to save user preferences from a sketch running either on a PC or an Android phone, using the same code in as standard "Java-way" as possible.
Ideal candidate for my purposes seems to be the java.util.prefs.Preferences class. So, I wrote a little test script to see if it's working in processing:
String prId = "counter";
Preferences prefs = Preferences.userNodeForPackage(this.getClass());
int counter = prefs.getInt(prId, 0);
println(counter);
prefs.putInt(prId, 1+counter);
This program outputs an increasing number each time it is executed - on a PC. On Android, the default value (0) is always shown.
Are there any additional steps required to get this working on Android? Permissions to be requested?
Are there any alternatives for saving name - value pairs on both platforms?
Obs.: "WRITE_EXTERNAL_STORAGE" permission is already enabled
This is a known Android bug unfortunately: https://code.google.com/p/android/issues/detail?id=22232
Basically the app does not have write permissions for the generated path, which should be a system-specific location where the user has write permissions instead.
Simplest (cross platform) workaround could be to use java.util.Properties, where you have control over the storage location.
Another workaround (if you are tied to the Preferences API for some reason) might be to provide your own implementation of AbstractPreferences (perhaps backed by Android SharedPreferences?), see this SO post: Is there a way to use java.util.Preferences under Windows without it using the Registry as the backend?
P.S.: Another workaround option might be to explicitly export / import the data using Preferences.exportSubtree(OutputStream os) and
Preferences.importPreferences(InputStream is)
In Android, the preferred way to store preferences is to make use of SharedPreferences. The equivalent code would be like this:
String prId = "counter";
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
int counter = prefs.getInt(prId,0); // Get int, default is 0
SharedPreferences.Editor prefsEditor = prefs.edit();
prefsEditor.putInt(prId, counter++); // Put counter back
prefsEditor.commit(); //Don't forget to commit the changes
I don't know exactly why java.util.prefs.Preferences would fail in Android. I suspect the reason is data would be deleted after the current Activity or the application is destroyed.
Because directory structure is different on each platform, it's hard to get preferences by just using one single same method. For example, data is stored in /.java/.userPrefs/**yourpacakgename**/prefs.xml on Android while it's in Registry on Windows and in ~/Library/Preferences/**yourpacakgename**/prefs.xml on Mac OS X. Also, you can't use Preferences.userRoot() in Android because an application cannot get root access.