Skip to content

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

kotlin
preferences().edit {
    putString("foo", "bar")
}

When reading preferences in a host, you can use the following in PackageParam.

The following example

kotlin
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

kotlin
// 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

kotlin
// 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

kotlin
// 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

kotlin
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

kotlin
// 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

kotlin
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

kotlin
// 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.

Released under the Apache-2.0 License