我是android开发的新手。 目前,我想对一个名为Shared Preference的自定义进行加密并与PreferenceScreen集成,但未能这样做。我正在使用依赖项:
我曾尝试研究有关这两个功能集成的相关信息,但未找到相关信息。
根据我的测试,我有一个现有的加密共享首选项,并测试了以下API:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
fragment.onActivityResult(requestCode, resultCode, data);
Log.d("Activity", "ON RESULT CALLED");
}
} catch (Exception e) {
Log.d("ERROR", e.toString());
}
}
但是最终将首选项保存为纯值。
我的问题:
答案 0 :(得分:2)
使用getPreferenceManager().setPreferenceDataStore(PreferenceDataStore)
。 PreferenceDataStore
可以更改加载/保存首选项的方式。
PreferenceDataStore
的简单实现:
public class SharedPreferenceDataStore extends PreferenceDataStore {
private final SharedPreferences mSharedPreferences;
public SharedPreferenceDataStore(@NonNull SharedPreferences sharedPreferences) {
mSharedPreferences = sharedPreferences;
}
@NonNull
public SharedPreferences getSharedPreferences() {
return mSharedPreferences;
}
@Override
public void putString(String key, @Nullable String value) {
mSharedPreferences.edit().putString(key, value).apply();
}
@Override
public void putStringSet(String key, @Nullable Set<String> values) {
mSharedPreferences.edit().putStringSet(key, values).apply();
}
@Override
public void putInt(String key, int value) {
mSharedPreferences.edit().putInt(key, value).apply();
}
@Override
public void putLong(String key, long value) {
mSharedPreferences.edit().putLong(key, value).apply();
}
@Override
public void putFloat(String key, float value) {
mSharedPreferences.edit().putFloat(key, value).apply();
}
@Override
public void putBoolean(String key, boolean value) {
mSharedPreferences.edit().putBoolean(key, value).apply();
}
@Nullable
@Override
public String getString(String key, @Nullable String defValue) {
return mSharedPreferences.getString(key, defValue);
}
@Nullable
@Override
public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
return mSharedPreferences.getStringSet(key, defValues);
}
@Override
public int getInt(String key, int defValue) {
return mSharedPreferences.getInt(key, defValue);
}
@Override
public long getLong(String key, long defValue) {
return mSharedPreferences.getLong(key, defValue);
}
@Override
public float getFloat(String key, float defValue) {
return mSharedPreferences.getFloat(key, defValue);
}
@Override
public boolean getBoolean(String key, boolean defValue) {
return mSharedPreferences.getBoolean(key, defValue);
}
}
getPreferenceManager().setPreferenceDataStore(new SharedPreferenceDataStore(EncryptedSharedPreferences.create()));
答案 1 :(得分:1)
将EncryptedSharePreferences与AndroidX首选项GUI集成时遇到一些问题。
PreferenceManager.getDefaultSharedPreferences(context);
没有相应的set方法。我创建的解决方案是不依赖于SharedPreferences,而是利用PreferenceFragmentCompat写入EncryptedPreferenceDataStore。但是,这仍然带来一个问题,直到用户进入“首选项”屏幕,默认值才被初始化。
依赖项
dependencies {
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.security:security-crypto:1.0.0-rc01'
}
首选项片段
import android.app.Activity;
import android.app.ActivityManager;
import android.os.Bundle;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
public class PreferencesFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.setPreferenceDataStore(EncryptedPreferenceDataStore.getInstance(getContext()));
// Load the preferences from an XML resource
setPreferencesFromResource(R.xml.preferences, rootKey);
}
EncryptedPreferenceDataStore
import android.content.Context;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceDataStore;
import androidx.security.crypto.EncryptedSharedPreferences;
import java.util.Set;
public class EncryptedPreferenceDataStore extends PreferenceDataStore {
private static final String CONFIG_FILE_NAME = "FileName";
private static final String CONFIG_MASTER_KEY_ALIAS = "KeyAlias";
private static EncryptedPreferenceDataStore mInstance;
private SharedPreferences mSharedPreferences;
private Context mContext;
private EncryptedPreferenceDataStore(Context context) {
try {
mContext = context;
mSharedPreferences = EncryptedSharedPreferences.create(
CONFIG_FILE_NAME,
CONFIG_MASTER_KEY_ALIAS,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, //for encrypting Keys
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ////for encrypting Values
);
} catch (Exception e) {
// Fallback
mSharedPreferences = context.getSharedPreferences(CONFIG_FILE_NAME, Context.MODE_PRIVATE);
}
}
@Override
public void putString(String key, @Nullable String value) {
mSharedPreferences.edit().putString(key, value).apply();
}
@Override
public void putStringSet(String key, @Nullable Set<String> values) {
mSharedPreferences.edit().putStringSet(key, values).apply();
}
@Override
public void putInt(String key, int value) {
mSharedPreferences.edit().putInt(key, value).apply();
}
@Override
public void putLong(String key, long value) {
mSharedPreferences.edit().putLong(key, value).apply();
}
@Override
public void putFloat(String key, float value) {
mSharedPreferences.edit().putFloat(key, value).apply();
}
@Override
public void putBoolean(String key, boolean value) {
mSharedPreferences.edit().putBoolean(key, value).apply();
}
@Nullable
@Override
public String getString(String key, @Nullable String defValue) {
return mSharedPreferences.getString(key, defValue);
}
@Nullable
@Override
public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
return mSharedPreferences.getStringSet(key, defValues);
}
@Override
public int getInt(String key, int defValue) {
return mSharedPreferences.getInt(key, defValue);
}
@Override
public long getLong(String key, long defValue) {
return mSharedPreferences.getLong(key, defValue);
}
@Override
public float getFloat(String key, float defValue) {
return mSharedPreferences.getFloat(key, defValue);
}
@Override
public boolean getBoolean(String key, boolean defValue) {
return mSharedPreferences.getBoolean(key, defValue);
}
}
用法
EncryptedPreferenceDataStore prefs = EncryptedPreferenceDataStore.getInstance(getContext());
boolean bIsXXX = prefs.getBoolean(getString(R.string.pref_access_xxx), true);
答案 2 :(得分:1)
这个问题可能是Java特有的,但是Kotlin在一段时间内是首选的一等公民。对于Kotlin来说,诀窍仍然是设置preferencesDataSource
,它是这样的:
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore =
EncryptedPreferenceDataStore.getInstance(requireContext())
// Load the preferences from an XML resource
setPreferencesFromResource(R.xml.preferences, rootKey)
}
EncryptedPreferenceDataStore
的Kotlin版本:我为单例使用also
关键字,类似于Singleton with parameter in Kotlin
class EncryptedPreferenceDataStore private constructor(context: Context) : PreferenceDataStore() {
companion object {
private const val SHARED_PREFERENCES_NAME = "secret_shared_preferences"
@Volatile private var INSTANCE: EncryptedPreferenceDataStore? = null
fun getInstance(context: Context): EncryptedPreferenceDataStore =
INSTANCE ?: synchronized(this) {
INSTANCE ?: EncryptedPreferenceDataStore(context).also { INSTANCE = it }
}
}
private var mSharedPreferences: SharedPreferences
private lateinit var mContext: Context
init {
try {
mContext = context
val masterKey = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
mSharedPreferences = EncryptedSharedPreferences.create(
context,
SHARED_PREFERENCES_NAME,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
} catch (e: Exception) {
// Fallback, default mode is Context.MODE_PRIVATE!
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
}
}
override fun putString(key: String, value: String?) {
mSharedPreferences.edit().putString(key, value).apply()
}
override fun putStringSet(key: String, values: Set<String>?) {
mSharedPreferences.edit().putStringSet(key, values).apply()
}
override fun putInt(key: String, value: Int) {
mSharedPreferences.edit().putInt(key, value).apply()
}
override fun putLong(key: String, value: Long) {
mSharedPreferences.edit().putLong(key, value).apply()
}
override fun putFloat(key: String, value: Float) {
mSharedPreferences.edit().putFloat(key, value).apply()
}
override fun putBoolean(key: String, value: Boolean) {
mSharedPreferences.edit().putBoolean(key, value).apply()
}
override fun getString(key: String, defValue: String?): String? {
return mSharedPreferences.getString(key, defValue)
}
override fun getStringSet(key: String, defValues: Set<String>?): Set<String>? {
return mSharedPreferences.getStringSet(key, defValues)
}
override fun getInt(key: String, defValue: Int): Int {
return mSharedPreferences.getInt(key, defValue)
}
override fun getLong(key: String, defValue: Long): Long {
return mSharedPreferences.getLong(key, defValue)
}
override fun getFloat(key: String, defValue: Float): Float {
return mSharedPreferences.getFloat(key, defValue)
}
override fun getBoolean(key: String, defValue: Boolean): Boolean {
return mSharedPreferences.getBoolean(key, defValue)
}
}
也许通过双重同步检查可以使线程更安全?