Skip to content

Commit 179b9d8

Browse files
committed
Refactor context and JavaObject handling, add ActivityThread
Refactored Context to use a new ActivityThread class for application context access and updated its API to use method-style accessors. Added a generic JavaObject.create<T>() proxy for dynamic Java object interaction, replacing the removed JavaObjectProxy. Improved SharedPreferences to use the new Context API and added error handling. Cleaned up and consolidated code for better maintainability and type safety.
1 parent 921e61c commit 179b9d8

File tree

8 files changed

+177
-171
lines changed

8 files changed

+177
-171
lines changed

ts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "wxu",
3-
"version": "0.0.92",
3+
"version": "0.0.93",
44
"type": "module",
55
"description": "WXU TypeScript Package",
66
"source": "src/index.ts",

ts/src/classes/Context.ts

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,42 @@
11
import { JavaObject } from "./JavaObject";
2+
import { ActivityThread } from "./android/app/ActivityThread";
3+
4+
export interface ContextWrapper {
5+
getApplicationContext(): any;
6+
}
7+
8+
export interface ContextImpl extends ContextWrapper {
9+
getPackageName(): string;
10+
getDataDir(): any;
11+
getCacheDir(): any;
12+
getExternalCacheDir(): any;
13+
getFilesDir(): any;
14+
getSystemService(name: string): any;
15+
getResources(): any;
16+
getPackageManager(): any;
17+
getContentResolver(): any;
18+
getApplicationInfo(): any;
19+
getAssets(): any;
20+
getSharedPreferences(name: string, mode: number): any;
21+
}
222

323
/**
424
* Provides access to Android application context and common context-related operations.
525
* Wraps the underlying JavaObject interactions for easier use in JavaScript/TypeScript.
626
*/
7-
export class Context {
27+
export class Context implements ContextImpl {
828
private static _instance: Context;
9-
private _context: JavaObject;
29+
private _context: ContextImpl;
1030

1131
private constructor() {
12-
// Initialize the base context using ActivityThread
13-
const ActivityThread = new JavaObject("android.app.ActivityThread");
14-
const thread = ActivityThread.call("currentActivityThread");
15-
const context = JavaObject.callMethod(thread!!, "getApplication", []);
16-
this._context = JavaObject.fromObjId(
17-
JavaObject.callMethod(context!!, "getApplicationContext", [])
18-
);
32+
const aThread = new ActivityThread();
33+
// ContextWrapper is basiclly `Context`
34+
const application = aThread.currentActivityThread().getApplication();
35+
this._context = application.getApplicationContext() as ContextImpl;
36+
}
37+
38+
public getApplicationContext() {
39+
return this;
1940
}
2041

2142
/**
@@ -28,101 +49,92 @@ export class Context {
2849
return Context._instance;
2950
}
3051

31-
/**
32-
* Gets the underlying JavaObject representing the Android context
33-
*/
34-
public get native(): JavaObject {
35-
return this._context;
52+
public getSharedPreferences(name: string, mode: number) {
53+
return this._context.getSharedPreferences(name, mode);
3654
}
3755

3856
/**
3957
* Gets the application's package name
4058
*/
41-
public get packageName(): string {
42-
return this._context.call("getPackageName", []) as string;
59+
public getPackageName(): string {
60+
return this._context.getPackageName();
4361
}
4462

4563
/**
4664
* Gets the application's data directory
4765
*/
48-
public get dataDir(): string {
49-
return this._context.call("getDataDir", []) as string;
66+
public getDataDir(): string {
67+
return this._context.getDataDir();
5068
}
5169

5270
/**
5371
* Gets the application's cache directory
5472
*/
55-
public get cacheDir(): string {
56-
return this._context.call("getCacheDir", []) as string;
73+
public getCacheDir(): string {
74+
return this._context.getCacheDir();
5775
}
5876

5977
/**
6078
* Gets the application's external cache directory (if available)
6179
*/
62-
public get externalCacheDir(): string | null | undefined {
63-
return this._context.call("getExternalCacheDir", []);
80+
public getExternalCacheDir(): string | null | undefined {
81+
return this._context.getExternalCacheDir();
6482
}
6583

6684
/**
6785
* Gets the application's files directory
6886
*/
69-
public get filesDir(): string {
70-
return this._context.call("getFilesDir", []) as string;
87+
public getFilesDir(): string {
88+
return this._context.getFilesDir();
7189
}
7290

7391
/**
7492
* Gets the system service with the given name
7593
* @param serviceName The name of the system service (e.g., "window", "power")
7694
*/
77-
public getSystemService(serviceName: string): JavaObject | null {
78-
const serviceId = this._context.call("getSystemService", [serviceName]);
79-
return serviceId ? JavaObject.fromObjId(serviceId) : null;
95+
public getSystemService(serviceName: string) {
96+
return this._context.getSystemService(serviceName);
8097
}
8198

8299
/**
83100
* Gets the resources object for the application
84101
*/
85-
public get resources(): JavaObject | null {
86-
const resourcesId = this._context.call("getResources", []);
87-
return resourcesId ? JavaObject.fromObjId(resourcesId) : null;
102+
public getResources() {
103+
return this._context.getResources();
88104
}
89105

90106
/**
91107
* Gets the package manager
92108
*/
93-
public get packageManager(): JavaObject | null {
94-
const pmId = this._context.call("getPackageManager", []);
95-
return pmId ? JavaObject.fromObjId(pmId) : null;
109+
public getPackageManager() {
110+
return this._context.getPackageManager();
96111
}
97112

98113
/**
99114
* Gets the content resolver
100115
*/
101-
public get contentResolver(): JavaObject | null {
102-
const crId = this._context.call("getContentResolver", []);
103-
return crId ? JavaObject.fromObjId(crId) : null;
116+
public getContentResolver() {
117+
return this._context.getContentResolver();
104118
}
105119

106120
/**
107121
* Gets the application info
108122
*/
109-
public get applicationInfo(): JavaObject | null {
110-
const aiId = this._context.call("getApplicationInfo", []);
111-
return aiId ? JavaObject.fromObjId(aiId) : null;
123+
public getApplicationInfo() {
124+
return this._context.getApplicationInfo();
112125
}
113126

114127
/**
115128
* Gets the assets manager
116129
*/
117-
public get assets(): JavaObject | null {
118-
const assetsId = this._context.call("getAssets", []);
119-
return assetsId ? JavaObject.fromObjId(assetsId) : null;
130+
public getAssets() {
131+
return this._context.getAssets();
120132
}
121133

122134
/**
123135
* Releases the underlying context resources
124136
*/
125137
public release(): void {
126-
this._context.release();
138+
(this._context as unknown as JavaObject).release();
127139
}
128140
}

ts/src/classes/JavaObject.ts

Lines changed: 74 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,15 @@ export class JavaObject {
5656

5757
static {
5858
if (typeof window["global"] === "undefined") {
59-
throw new Error(
60-
"JavaObject requires a global context with 'wx:reflect' module."
61-
);
59+
throw new Error("JavaObject requires a global context with 'wx:reflect' module.");
6260
}
6361

6462
this.reflect = window.global.require("wx:reflect");
6563
this.proxyHandlers = new Map();
6664
this.nextProxyId = 0;
6765
}
6866

69-
public constructor(
70-
className: string | null,
71-
args: Array<string | boolean | number> = []
72-
) {
67+
public constructor(className: string | null, args: Array<string | boolean | number> = []) {
7368
if (typeof className === "undefined") {
7469
throw new TypeError("Class name must be a non-empty string or null.");
7570
}
@@ -80,10 +75,7 @@ export class JavaObject {
8075
}
8176
}
8277

83-
public call(
84-
method: string,
85-
args: Array<string | boolean | number> = []
86-
): string | null | undefined {
78+
public call(method: string, args: Array<string | boolean | number> = []): string | null | undefined {
8779
if (typeof method !== "string" || method.length === 0) {
8880
throw new TypeError("Method name must be a non-empty string.");
8981
}
@@ -119,44 +111,26 @@ export class JavaObject {
119111
return this.reflect?.getClass(name);
120112
}
121113

122-
public static newInstance(
123-
classId: string,
124-
args: Array<string | boolean | number> | null
125-
): string | null | undefined {
114+
public static newInstance(classId: string, args: Array<string | boolean | number> | null): string | null | undefined {
126115
const jsonArgs = args == null ? "null" : JSON.stringify(args);
127116
return this.reflect?.newInstance(classId, jsonArgs);
128117
}
129118

130-
public static callMethod(
131-
objId: string,
132-
method: string,
133-
args: Array<string | boolean | number> | null
134-
): string | null | undefined {
119+
public static callMethod(objId: string, method: string, args: Array<string | boolean | number> | null): string | null | undefined {
135120
const jsonArgs = args == null ? "[]" : JSON.stringify(args);
136121
return this.reflect?.callMethod(objId, method, jsonArgs);
137122
}
138123

139-
public static callStaticMethod(
140-
objId: string,
141-
method: string,
142-
args: Array<string | boolean | number> | null
143-
): string | null | undefined {
124+
public static callStaticMethod(objId: string, method: string, args: Array<string | boolean | number> | null): string | null | undefined {
144125
const jsonArgs = args == null ? "[]" : JSON.stringify(args);
145126
return this.reflect?.callStaticMethod(objId, method, jsonArgs);
146127
}
147128

148-
public static getField(
149-
objId: string,
150-
field: string
151-
): string | null | undefined {
129+
public static getField(objId: string, field: string): string | null | undefined {
152130
return this.reflect?.getField(objId, field);
153131
}
154132

155-
public static setField(
156-
objId: string,
157-
field: string,
158-
value: string | boolean | number | null
159-
): void {
133+
public static setField(objId: string, field: string, value: string | boolean | number | null): void {
160134
this.reflect?.setField(objId, field, String(value));
161135
}
162136

@@ -199,10 +173,7 @@ export class JavaObject {
199173
}
200174
}
201175

202-
const proxyId = this.reflect?.createProxy(
203-
interfaceName,
204-
JSON.stringify(methodsMap)
205-
);
176+
const proxyId = this.reflect?.createProxy(interfaceName, JSON.stringify(methodsMap));
206177

207178
const proxy = JavaObject.fromObjId(proxyId);
208179

@@ -213,4 +184,69 @@ export class JavaObject {
213184

214185
return proxy;
215186
}
187+
188+
public static create<T>(className: string | JavaObject | null, args: any[] = []): T {
189+
let javaObj: JavaObject;
190+
191+
if (className instanceof JavaObject) {
192+
javaObj = className;
193+
} else if (className) {
194+
javaObj = new JavaObject(className, args);
195+
} else {
196+
throw new TypeError("Must provide a class name or a JavaObject instance");
197+
}
198+
199+
const autoWrap = (value: any) => {
200+
if (value == null) {
201+
return value;
202+
}
203+
204+
if (typeof value === "string") {
205+
let objId = value;
206+
207+
if (value.startsWith("ptr:")) {
208+
objId = value.slice(4);
209+
}
210+
211+
if (objId.includes("wx_reflect_obj") || objId.match(/^[a-zA-Z0-9_]+$/)) {
212+
try {
213+
return this.create(JavaObject.fromObjId(objId));
214+
} catch (error) {
215+
console.error(`Error wrapping Java object ${objId}:`, error);
216+
return value;
217+
}
218+
}
219+
}
220+
221+
return value;
222+
};
223+
224+
return new Proxy(javaObj, {
225+
get(target, prop: string, receiver) {
226+
if (prop === "release" || prop === "objId" || prop === "classId") {
227+
return Reflect.get(target, prop, receiver);
228+
}
229+
230+
return (...args: any[]) => {
231+
try {
232+
const result = JavaObject.callMethod(target.objId, prop, args);
233+
return autoWrap(result);
234+
} catch (error) {
235+
console.error(`Error calling method ${prop}:`, error);
236+
throw error;
237+
}
238+
};
239+
},
240+
241+
set(target, prop: string, value) {
242+
try {
243+
JavaObject.setField(target.objId, prop, value);
244+
return true;
245+
} catch (error) {
246+
console.error(`Error setting field ${prop}:`, error);
247+
return false;
248+
}
249+
},
250+
}) as T;
251+
}
216252
}

0 commit comments

Comments
 (0)