-
Notifications
You must be signed in to change notification settings - Fork 632
New XSharedPreferences
Since EdXposed API 93, a new XSharedPreferences
is provided targeted for modules with sdk > 27. Modules developers can enable this new XSharedPreferences
support by modifying the meta-data of your modules to set xposedminversion
to 93 or above, or add xposedsharedprefs
meta-data.
When enabled, EdXposed will automatically hook ContextImpl.getPreferencesDir()
so that your Context.getSharedPreferences
and PreferenceFragment
could work without further modification. Also, EdXposed hooks ContextImpl.checkMode(int)
so that you can easily get a world readable shared preference by passing Context.MODE_WORLD_READABLE
to Context.getSharedPreferences
.
If you are using xposedsharedprefs
meta-data to indicate your module will use this new feature, you probably want to ensure this feature is working properly. The following code snippet will do the magic:
Java
SharedPreferences pref;
try {
pref = context.getSharedPreferences(MY_PREF_NAME, Context.MODE_WORLD_READABLE);
} catch (SecurityException ignored) {
// The new XSharedPreferences is not enabled or module's not loading
pref = null; // other fallback, if any
}
Kotlin
val pref = try {
context.getSharedPreferences(MY_PREF_NAME, Context.MODE_WORLD_READABLE)
} catch (e: SecurityException) {
// The new XSharedPreferences is not enabled or module's not loading
null // other fallback, if any
}
Notice that EdXposed will help you to make the preference world readable if and only if you are getting preference in mode Context.MODE_WORLD_READABLE
.
To read the preference from the hooked app, you can simply use XSharedPreferences(String packageName)
or XSharedPreferences(String packageName, String prefFileName)
to retrieve the preference. Notice that you cannot use the XSharedPreferences(File prefFile)
because the preference file is stored in a random directory.
You should check the permission before you read anything from the module. You should also load the preference if you need it. Try to split the preference file to multiple files for different purposes. Here's an example:
Java
public class XposedInit implements IXposedHookLoadPackage, IXposedHookZygoteInit, IXposedHookInitPackageResources {
private static SharedPreferences getPref(String path) {
SharedPreferences pref = new XSharedPreferences(BuildConfig.APPLICATION_ID, path);
return pref.getFile().canRead() ? pref : null;
}
@Override
public void initZygote(IXposedHookZygoteInit.StartupParam startupParam) {
SharedPreferences pref = getPref("zygote_conf");
if (pref != null) {
// do things with it
} else {
Log.e(TAG, "Cannot load pref for zygote properly");
}
}
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
SharedPreferences pref;
switch (lpparam.packageName) {
case PACKAGE_NAME_A:
pref = getPref("a_conf");
if (pref != null) {
// do things with it for A
} else {
Log.e(TAG, "Cannot load pref for A properly");
}
break;
case PACKAGE_NAME_B:
pref = getPref("b_conf");
if (pref != null) {
// do things with it for B
} else {
Log.e(TAG, "Cannot load pref for B properly");
}
break;
case BuildConfig.APPLICATION_ID:
// hook myself
break;
default:
// skip
}
}
@Override
public void handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam resparam) {
// similar to handleLoadPackage
}
}
Kotlin
class XposedInit : IXposedHookLoadPackage, IXposedHookZygoteInit, IXposedHookInitPackageResources {
companion object {
fun getPref(path: String) : SharedPreferences? {
val pref = XSharedPreferences(BuildConfig.APPLICATION_ID, path)
return if(pref.file.canRead()) pref else null
}
// lazy loads when needed
val prefForZygote by lazy { getPref("zygote_conf") }
// lazy loads when needed
val prefForA by lazy { getPref("a_conf") }
// lazy loads when needed
val prefForB by lazy { getPref("b_conf") }
}
override fun initZygote(startupParam: StartupParam) {
prefForZygote?.let {
// do things with it
} ?: Log.e(TAG, "Cannot load pref for zygote properly")
}
override fun handleLoadPackage(lpparam: LoadPackageParam) {
when(lpparam.packageName) {
PACKAGE_NAME_A -> {
prefForA?.let {
// do things with it for A
} ?: Log.e(TAG, "Cannot load pref for A properly")
}
PACKAGE_NAME_B -> {
prefForB?.let {
// do things with it for B
} ?: Log.e(TAG, "Cannot load pref for B properly")
}
BuildConfig.APPLICATION_ID -> {
// hook myself
}
default -> {
// skip
}
}
}
override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam) {
// similar to handleLoadPackage
}
}
EdXposed Official Wiki