class JavaObject { static { this.reflect = global.require("wx:reflect"); this.proxyHandlers = new Map(); this.nextProxyId = 0; } constructor(className, args = []) { if (className) { this.classId = JavaObject.getClass(className); this.objId = JavaObject.newInstance(this.classId, args); } } call(method, args = []) { return JavaObject.callMethod(this.objId, method, args); } get(field) { return JavaObject.getField(this.objId, field); } set(field, value) { JavaObject.setField(this.objId, field, value); } release() { JavaObject.release(this.objId); } static getClass(name) { return this.reflect.getClass(name); } static newInstance(classId, args) { const jsonArgs = (args == null) ? "null" : JSON.stringify(args); return this.reflect.newInstance(classId, jsonArgs); } static callMethod(objId, method, args) { const jsonArgs = (args == null) ? "[]" : JSON.stringify(args); return this.reflect.callMethod(objId, method, jsonArgs); } static getField(objId, field) { return this.reflect.getField(objId, field); } static setField(objId, field, value) { this.reflect.setField(objId, field, value); } static release(objId) { this.reflect.releaseObject(objId); } static fromObjId(objId) { const obj = new JavaObject(null); obj.objId = objId; return obj; } static createProxy(interfaceName, handler) { const methodsMap = {}; const handlerIds = []; const allMethods = { hashCode: () => 0, equals: () => false, toString: () => '[JavaScript Proxy]', ...handler }; for (const methodName in allMethods) { if (typeof allMethods[methodName] === 'function') { const methodId = `proxy_handler_${this.nextProxyId++}`; methodsMap[methodName] = methodId; handlerIds.push(methodId); this.proxyHandlers.set(methodId, (...args) => { try { return allMethods[methodName](...args); } catch (e) { console.error(`Error in proxy method ${methodName}:`, e); if (methodName === 'equals') return false; return null; } }); } } const proxyId = this.reflect.createProxy(interfaceName, JSON.stringify(methodsMap)); const proxy = JavaObject.fromObjId(proxyId); proxy.releaseProxy = () => { handlerIds.forEach(id => this.proxyHandlers.delete(id)); proxy.release(); }; return proxy; } } class SharedPreferences { #prefsId; #editorId = null; #listeners = new Map(); #listenerProxy = null; constructor(context, name, mode = 0) { const contextObj = (context instanceof JavaObject) ? context : JavaObject.fromObjId(context); this.#prefsId = contextObj.call("getSharedPreferences", [name, mode]); } #getEditor() { if (!this.#editorId) { this.#editorId = JavaObject.callMethod(this.#prefsId, "edit", []); } return this.#editorId; } get(key, defaultValue = null) { const type = typeof defaultValue; switch (type) { case 'boolean': return JavaObject.callMethod(this.#prefsId, "getBoolean", [key, defaultValue]) == "true"; case 'number': if (Number.isInteger(defaultValue)) { const int = JavaObject.callMethod(this.#prefsId, "getInt", [key, defaultValue]) const parsedInt = Number.parseInt(int) if (Number.isNaN(parsedInt)) { return defaultValue } return parsedInt } const float = JavaObject.callMethod(this.#prefsId, "getFloat", [key, defaultValue]) const parsedFloat = Number.parseFloat(float) if (Number.isNaN(parsedFloat)) { return defaultValue } return parsedFloat case 'string': return JavaObject.callMethod(this.#prefsId, "getString", [key, defaultValue]); default: return JavaObject.callMethod(this.#prefsId, "getString", [key, String(defaultValue)]); } } put(key, value) { const editor = this.#getEditor(); const type = typeof value; switch (type) { case 'boolean': JavaObject.callMethod(editor, "putBoolean", [key, value]); break; case 'number': Number.isInteger(value) ? JavaObject.callMethod(editor, "putInt", [key, value]) : JavaObject.callMethod(editor, "putFloat", [key, value]); break; case 'string': JavaObject.callMethod(editor, "putString", [key, value]); break; default: JavaObject.callMethod(editor, "putString", [key, String(value)]); } return this; } remove(key) { JavaObject.callMethod(this.#getEditor(), "remove", [key]); return this; } clear() { JavaObject.callMethod(this.#getEditor(), "clear", []); return this; } commit() { if (!this.#editorId) return false; const result = JavaObject.callMethod(this.#editorId, "commit", []); this.#editorId = null; return result; } apply() { if (!this.#editorId) return; JavaObject.callMethod(this.#editorId, "apply", []); this.#editorId = null; } contains(key) { return JavaObject.callMethod(this.#prefsId, "contains", [key]); } getAll() { return JavaObject.callMethod(this.#prefsId, "getAll", []); } registerOnChangeListener(callback) { if (typeof callback !== 'function') { throw new Error('Callback must be a function'); } const listenerId = `listener_${Math.random().toString(36).substring(2, 9)}`; this.#listeners.set(listenerId, callback); if (!this.#listenerProxy) { const interfaceName = "android.content.SharedPreferences$OnSharedPreferenceChangeListener"; this.#listenerProxy = JavaObject.createProxy(interfaceName, { onSharedPreferenceChanged: (prefsId, key) => { this.#listeners.forEach(listener => { try { listener(key, this); } catch (e) { console.error('Error in preference change listener:', e); } }); }, }); JavaObject.callMethod(this.#prefsId, "registerOnSharedPreferenceChangeListener", [this.#listenerProxy.objId]); } return () => this.unregisterOnChangeListener(listenerId); } unregisterOnChangeListener(listenerId) { if (this.#listeners.delete(listenerId) && this.#listeners.size === 0 && this.#listenerProxy) { JavaObject.callMethod(this.#prefsId, "unregisterOnSharedPreferenceChangeListener", [this.#listenerProxy.objId]); this.#listenerProxy.releaseProxy(); this.#listenerProxy = null; return true; } return false; } } window.context = (() => { const ActivityThread = new JavaObject("android.app.ActivityThread"); const thread = ActivityThread.call("currentActivityThread"); const context = JavaObject.callMethod(thread, "getApplication", []); return JavaObject.callMethod(context, "getBaseContext", []); })() window.prefs = new SharedPreferences(window.context, "my_prefs"); const unregister = prefs.registerOnChangeListener((key) => { console.log(`Preference changed: ${key}`); }); prefs.put("username", "john_doe") .put("user_id", 12345) .put("premium_user", false) .apply(); const username = prefs.get("username", ""); const userId = prefs.get("user_id", 0); const isPremium = prefs.get("premium_user", false); console.log(`User:`, username, `, ID:`, userId, `, Premium:`, isPremium);