fix(modules): register all native methods in onContext
This commit is contained in:
parent
f015246e94
commit
c0045b2e1e
2 changed files with 82 additions and 54 deletions
|
|
@ -1,68 +1,93 @@
|
|||
package io.github.revenge.xposed.modules
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.AtomicFile
|
||||
import io.github.revenge.xposed.Module
|
||||
import io.github.revenge.xposed.Utils.Log
|
||||
import io.github.revenge.xposed.modules.bridge.BridgeModule
|
||||
import java.io.*
|
||||
|
||||
/**
|
||||
* A module for caching versioned modules finds and blacklist, and assets mappings.
|
||||
*
|
||||
* See [ModulesCache] and [AssetsCache] for the cache structure.
|
||||
*
|
||||
* ## Methods
|
||||
*
|
||||
* ### Modules cache
|
||||
*
|
||||
* - `revenge.caches.modules.read() : { blacklist: number[], finds: { [filter: string]: { [id: string]: number } | null }, version: number } | null`
|
||||
* - Reads the modules cache. Returns `null` if the cache file does not exist or is invalid.
|
||||
*
|
||||
* - `revenge.caches.modules.write(blacklist: number[], finds: { [filter: string]: { [id: string]: number } | null }) : void`
|
||||
* - Writes the modules cache.
|
||||
*
|
||||
* ### Assets cache
|
||||
*
|
||||
* - `revenge.caches.assets.read() : { data: { [name: string]: { [type: string]: number } }, version: number } | null`
|
||||
* - Reads the assets cache. Returns `null` if the cache file does not exist or is invalid.
|
||||
*
|
||||
* - `revenge.caches.assets.write(data: { [name: string]: { [type: string]: number } }) : void`
|
||||
* - Writes the assets cache.
|
||||
*
|
||||
* The caches are versioned and tied to the app version code. When the app is updated,
|
||||
* the caches are invalidated and new cache files are created.
|
||||
*/
|
||||
class CacheModule : Module() {
|
||||
private val CACHE_DIR = "revenge"
|
||||
private companion object {
|
||||
const val CACHE_DIR = "revenge"
|
||||
|
||||
private val MODULES_CACHE_PREFIX = "modules"
|
||||
private val ASSETS_CACHE_PREFIX = "assets"
|
||||
const val MODULES_CACHE_PREFIX = "modules"
|
||||
const val ASSETS_CACHE_PREFIX = "assets"
|
||||
}
|
||||
|
||||
private lateinit var modulesCache: ModulesCache
|
||||
private lateinit var assetsCache: AssetsCache
|
||||
|
||||
override fun onActivity(activity: Activity) = with(activity) {
|
||||
override fun onContext(context: Context) = with(context) {
|
||||
val revengeCacheDir = File(cacheDir, CACHE_DIR).apply { asDir() }
|
||||
val (_, _, _, versionCode) = getAppInfo()
|
||||
|
||||
val modulesCacheFile =
|
||||
File(
|
||||
revengeCacheDir,
|
||||
"$MODULES_CACHE_PREFIX.$versionCode"
|
||||
).apply { asFile() }
|
||||
val assetsCacheFile =
|
||||
File(
|
||||
revengeCacheDir,
|
||||
"$ASSETS_CACHE_PREFIX.$versionCode"
|
||||
).apply { asFile() }
|
||||
val modulesCacheFile = File(
|
||||
revengeCacheDir, "$MODULES_CACHE_PREFIX.$versionCode"
|
||||
).apply { asFile() }
|
||||
|
||||
val assetsCacheFile = File(
|
||||
revengeCacheDir, "$ASSETS_CACHE_PREFIX.$versionCode"
|
||||
).apply { asFile() }
|
||||
|
||||
BridgeModule.registerMethod("revenge.caches.modules.read") {
|
||||
if (::modulesCache.isInitialized) modulesCache.toMap() else null
|
||||
if (::modulesCache.isInitialized) modulesCache.toMap() else ModulesCache.loadFromFileOrNull(modulesCacheFile)
|
||||
?.let {
|
||||
modulesCache = it
|
||||
it.toMap()
|
||||
}
|
||||
}
|
||||
|
||||
BridgeModule.registerMethod("revenge.caches.modules.write") {
|
||||
val (blacklist, finds) = it
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
modulesCache =
|
||||
ModulesCache(
|
||||
blacklist as ArrayList<Double>,
|
||||
finds as HashMap<String, HashMap<String, Double>?>
|
||||
)
|
||||
.apply { saveToFile(modulesCacheFile) }
|
||||
Log.i("Modules cache saved: ${modulesCacheFile.absolutePath}")
|
||||
modulesCache = ModulesCache(
|
||||
blacklist as ArrayList<Double>, finds as HashMap<String, HashMap<String, Double>?>
|
||||
).apply { saveToFile(modulesCacheFile) }
|
||||
Log.i("Modules cache saved: ${modulesCacheFile.absolutePath} (blacklisted: ${blacklist.size}, finds: ${finds.size})")
|
||||
}
|
||||
|
||||
BridgeModule.registerMethod("revenge.caches.assets.read") {
|
||||
if (::assetsCache.isInitialized) assetsCache.toMap() else null
|
||||
if (::assetsCache.isInitialized) assetsCache.toMap() else AssetsCache.loadFromFileOrNull(assetsCacheFile)
|
||||
?.let {
|
||||
assetsCache = it
|
||||
it.toMap()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BridgeModule.registerMethod("revenge.caches.assets.write") {
|
||||
val (data) = it
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
assetsCache =
|
||||
AssetsCache(data as HashMap<String, HashMap<String, Double>>)
|
||||
.apply { saveToFile(assetsCacheFile) }
|
||||
Log.i("Assets cache saved: ${assetsCacheFile.absolutePath}")
|
||||
AssetsCache(data as HashMap<String, HashMap<String, Double>>).apply { saveToFile(assetsCacheFile) }
|
||||
Log.i("Assets cache saved: ${assetsCacheFile.absolutePath} (count: ${data.size})")
|
||||
}
|
||||
|
||||
return@with
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,8 +95,7 @@ private class CacheVersionMismatchException(expected: Int, actual: Int) :
|
|||
Throwable("Expected cache version: $expected, but got version: $actual")
|
||||
|
||||
data class ModulesCache(
|
||||
val blacklist: List<Double>,
|
||||
val finds: Map<String, Map<String, Double>?>
|
||||
val blacklist: List<Double>, val finds: Map<String, Map<String, Double>?>
|
||||
) {
|
||||
fun saveToFile(file: File) {
|
||||
val atomic = AtomicFile(file)
|
||||
|
|
@ -89,7 +113,7 @@ data class ModulesCache(
|
|||
// Write finds
|
||||
out.writeInt(finds.size)
|
||||
for ((filter, matches) in finds) {
|
||||
out.writeUTF(filter) // replaces writeUTF
|
||||
out.writeUTF(filter)
|
||||
if (matches == null) {
|
||||
out.writeBoolean(false) // null marker
|
||||
} else {
|
||||
|
|
@ -111,8 +135,7 @@ data class ModulesCache(
|
|||
}
|
||||
|
||||
fun toMap(): Map<String, Any> {
|
||||
val findsMap =
|
||||
finds.mapValues { (_, matches) -> matches?.map { (k, v) -> k to v }?.toMap() }
|
||||
val findsMap = finds.mapValues { (_, matches) -> matches?.map { (k, v) -> k to v }?.toMap() }
|
||||
|
||||
return mapOf("blacklist" to blacklist, "finds" to findsMap, "version" to VERSION)
|
||||
}
|
||||
|
|
@ -126,8 +149,7 @@ data class ModulesCache(
|
|||
try {
|
||||
DataInputStream(BufferedInputStream(atomic.openRead())).use { input ->
|
||||
val version = input.readInt()
|
||||
if (version != VERSION)
|
||||
throw CacheVersionMismatchException(VERSION, version)
|
||||
if (version != VERSION) throw CacheVersionMismatchException(VERSION, version)
|
||||
|
||||
val blacklistSize = input.readInt()
|
||||
val blacklist = MutableList(blacklistSize) { input.readInt().toDouble() }
|
||||
|
|
@ -200,8 +222,7 @@ data class AssetsCache(
|
|||
return mapOf(
|
||||
"data" to data.mapValues { (_, mappings) ->
|
||||
mappings.map { (type, id) -> type to id }.toMap()
|
||||
},
|
||||
"version" to VERSION
|
||||
}, "version" to VERSION
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -214,8 +235,7 @@ data class AssetsCache(
|
|||
try {
|
||||
DataInputStream(BufferedInputStream(atomic.openRead())).use { input ->
|
||||
val version = input.readInt()
|
||||
if (version != VERSION)
|
||||
throw CacheVersionMismatchException(VERSION, version)
|
||||
if (version != VERSION) throw CacheVersionMismatchException(VERSION, version)
|
||||
|
||||
val dataSize = input.readInt()
|
||||
val data = mutableMapOf<String, Map<String, Double>>()
|
||||
|
|
|
|||
|
|
@ -1,24 +1,36 @@
|
|||
package io.github.revenge.xposed.modules
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.AtomicFile
|
||||
import io.github.revenge.xposed.Module
|
||||
import io.github.revenge.xposed.Utils.Log
|
||||
import io.github.revenge.xposed.modules.bridge.BridgeModule
|
||||
import java.io.*
|
||||
|
||||
/**
|
||||
* Manages the states of plugins, allowing reading and writing of plugin states to a file.
|
||||
*
|
||||
* ## Methods
|
||||
*
|
||||
* - `revenge.plugins.states.read(): { flags: { [pluginId: string]: number } }`
|
||||
* - Reads the current plugin states from the file and returns them as a map.
|
||||
*
|
||||
* - `revenge.plugins.states.write(flags: { [pluginId: string]: number }): void`
|
||||
* - Writes the provided plugin states to the file.
|
||||
*/
|
||||
class PluginsModule : Module() {
|
||||
private val DATA_DIR = "revenge/plugins"
|
||||
private val STATES_FILE = "states"
|
||||
private companion object {
|
||||
const val DATA_DIR = "revenge/plugins"
|
||||
const val STATES_FILE = "states"
|
||||
}
|
||||
|
||||
private lateinit var states: PluginStates
|
||||
|
||||
override fun onActivity(activity: Activity) = with(activity) {
|
||||
override fun onContext(context: Context) = with(context) {
|
||||
val dataDir = File(filesDir, DATA_DIR)
|
||||
|
||||
val statesFile = File(
|
||||
dataDir,
|
||||
STATES_FILE
|
||||
dataDir, STATES_FILE
|
||||
).apply { asFile() }
|
||||
|
||||
BridgeModule.registerMethod("revenge.plugins.states.read") {
|
||||
|
|
@ -32,15 +44,11 @@ class PluginsModule : Module() {
|
|||
BridgeModule.registerMethod("revenge.plugins.states.write") {
|
||||
val (flags) = it
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
states =
|
||||
PluginStates(
|
||||
flags as Map<String, Double>
|
||||
)
|
||||
.apply { saveToFile(statesFile) }
|
||||
states = PluginStates(
|
||||
flags as Map<String, Double>
|
||||
).apply { saveToFile(statesFile) }
|
||||
Log.i("Plugin states saved: ${statesFile.absolutePath}")
|
||||
}
|
||||
|
||||
return@with
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue