feat(lib/modules): support native to JS bridge
This commit is contained in:
parent
ddb02d2887
commit
00047da9b3
2 changed files with 62 additions and 0 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import { getCurrentStack, getErrorStack } from '@revenge-mod/utils/error'
|
||||
|
||||
const turboModuleProxy = globalThis.__turboModuleProxy
|
||||
|
||||
/**
|
||||
|
|
@ -103,6 +105,61 @@ export function getBridgeInfo(): BridgeInfo | null {
|
|||
}
|
||||
}
|
||||
|
||||
type AnyFunction = (...args: any[]) => any
|
||||
|
||||
const CallableReturnNativeMethodName = 'revenge.__callableReturn' as const
|
||||
const CallableModuleName = 'RevengeBridge'
|
||||
const ExposedJSMethods: {
|
||||
[methodName: string]: AnyFunction
|
||||
} = {}
|
||||
|
||||
/**
|
||||
* Registers a JS method that can be called from native code.
|
||||
*
|
||||
* @param name The name of the method to register.
|
||||
* @param method The method implementation.
|
||||
*/
|
||||
export function registerJSMethod(name: string, method: AnyFunction) {
|
||||
if (__DEV__ && ExposedJSMethods[name])
|
||||
nativeLoggingHook(
|
||||
`\u001b[33mWarning: Overwriting existing registered JS method: ${name}\n${getCurrentStack()}\u001b[0m`,
|
||||
1,
|
||||
)
|
||||
|
||||
ExposedJSMethods[name] = _wrapJSMethod(method)
|
||||
}
|
||||
|
||||
function _wrapJSMethod(method: AnyFunction) {
|
||||
return (...args: any[]) => {
|
||||
try {
|
||||
const ret = method(...args)
|
||||
_returnJSCall({ result: ret ?? null })
|
||||
} catch (error) {
|
||||
_returnJSCall({ error: getErrorStack(error) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _returnJSCall(payload: object) {
|
||||
callBridgeMethodSync(CallableReturnNativeMethodName, [payload])
|
||||
}
|
||||
|
||||
RN$registerCallableModule(
|
||||
CallableModuleName,
|
||||
() =>
|
||||
new Proxy(ExposedJSMethods, {
|
||||
get(target, prop: string) {
|
||||
const method = target[prop]
|
||||
if (!method)
|
||||
return () => {
|
||||
// Can't catch this native side, this will crash the app
|
||||
throw new Error(`JS method not found: ${prop}`)
|
||||
}
|
||||
return method
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
export interface BridgeInfo {
|
||||
name: string
|
||||
version: number
|
||||
|
|
@ -114,4 +171,5 @@ export type MethodResult<T extends MethodName> = Methods[T][1]
|
|||
|
||||
export interface Methods {
|
||||
'revenge.info': [[], BridgeInfo]
|
||||
[CallableReturnNativeMethodName]: [[payload: object], void]
|
||||
}
|
||||
|
|
|
|||
4
types/globals.d.ts
vendored
4
types/globals.d.ts
vendored
|
|
@ -109,6 +109,10 @@ declare global {
|
|||
var nativeModuleProxy: Record<string, unknown>
|
||||
var __turboModuleProxy: ((name: string) => unknown) | undefined
|
||||
function nativeLoggingHook(str: string, level: number): void
|
||||
function RN$registerCallableModule(
|
||||
name: string,
|
||||
moduleProvider: () => object,
|
||||
): void
|
||||
function alert(message: unknown): void
|
||||
function queueMicrotask(cb: () => void): void
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue