Module Preferences
This is a solution for sharing the private preferences of the module with hosts.
We need to store the preferences of the module for hosts to use, and the native SharedPreferences cannot share the stored data between them.
YukiHook provides YukiHookPreferences, which automatically chooses a suitable storage solution based on the base module you use.
Availability
This feature heavily depends on the solution provided by the current hook framework, and is affected by the system environment the module runs in.
YukiHook uses the XSharedPreferences solution in modules built with the yukihook-runtime-xposed82 base module, and the remote SharedPreferences solution in modules built with the yukihook-runtime-libxposed base module.
Notice
In modules using the yukihook-runtime-xposed82 base module, it is recommended to use it after observing the availability of the framework service, for details please refer to Module Status → Hook Framework Service Status.
LSPosed
In 1.9.0 and above, please build your module with the yukihook-runtime-libxposed base module directly, which is currently the most stable solution.
If you are still building your module with the yukihook-runtime-xposed82 base module, you need to raise the module's xposedminversion to 93 and add the xposedsharedprefs metadata in the AndroidManifest.xml to enable New XSharedPreferences.
However, this feature has been marked as deprecated since 2.1.0, and its selinux compatibility issues, which have existed since 1.9.0+, have never been solved, so we no longer recommend using New XSharedPreferences. According to the official announcement of LSPosed, it will be removed in version 2.3.0.
Vector
This is a third-party fork of LSPosed with features similar to LSPosed for now, but we have not tested it, so we make no guarantee of its compatibility.
EdXposed
The project is no longer updated. If you are using it on old devices, YukiHook still uses the XSharedPreferences solution, and we make no guarantee of its compatibility.
Not Listed
For hook frameworks that are not listed, as long as they are implemented according to the API specification provided by the base module, YukiHook still chooses a suitable storage solution based on the base module type.
Basic Usage
When storing preferences in the module, if you are in a place with a Context such as an Activity, you can use the following.
The following example
preferences().edit {
putString("foo", "bar")
}When reading preferences in a host, you can use the following in PackageParam.
The following example
val value = preferences.getString("foo", "default")To split preferences into areas, you can specify the name of each storage file.
Use it like this in the module.
The following example
// Recommended usage.
preferences("challenge").edit {
putString("foo", "bar")
}
// It can also be used like this.
preferences().name("challenge").edit {
putString("foo", "bar")
}Read it like this in a host.
The following example
// Recommended usage.
val value = preferences("challenge").getString("foo", "default")
// It can also be used like this.
val value = preferences.name("challenge").getString("foo", "default")You can call edit in the following two ways to store preferences in batches.
The following example
// Option 1
preferences().edit {
putString("foo-1", "bar-1")
putString("foo-2", "bar-2")
}
// Option 2
preferences().edit()
.putString("foo-1", "bar-1")
.putString("foo-2", "bar-2")
.apply()Notice
The preferences of the module are read-only in hosts, changes made in a host are ignored.
You can use isAvailable to check whether the current storage is available, and isWritable to check whether it is writable.
Use Templates
If your project has a lot of fixed preferences to store and read, it is recommended to create templates with PreferenceData.
The following example
object Feature {
val Foo = PreferenceData("foo", "default")
}Then use get and put to read and store preferences, the default value of the template is used when no default value is given.
The following example
// Store in the module.
preferences().edit {
put(Feature.Foo, "bar")
}
// Read in a host.
val value = preferences.get(Feature.Foo)Use in PreferenceFragment
If your module uses PreferenceFragmentCompat, you can move its subclasses to ModulePreferenceFragment.
The following example
class SettingsFragment : ModulePreferenceFragment() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
super.onCreatePreferences(savedInstanceState, rootKey)
setPreferencesFromResource(R.xml.settings_preferences, rootKey)
}
}Pay Attention
You must inherit ModulePreferenceFragment to store preferences in YukiHookPreferences.
Use Native Storage
In the module environment, YukiHookPreferences stores preferences in the shared location chosen by the base module by default.
If you want to store preferences directly in the private directory of the current module or host environment, you can use the native function.
The following example
// Store private preferences.
preferences.native().edit {
putBoolean("isolation", true)
}
// Read private preferences.
val isolation = preferences.native().getBoolean("isolation")
// Read shared preferences.
val shared = preferences.getBoolean("shared")After using native, data is stored and read in the private directory of the corresponding environment in both the module and hosts, they are isolated from each other, and hosts can also write preferences in this case.
Notice
Using native in a host requires the Application of the host to be created, otherwise an exception is thrown. You can use it in onCreate of the Host Lifecycle.