Java.perform(() => { // Register a new WebAppInterface Javascript environment const WebView = Java.use('android.webkit.WebView'); const WebAppInterface = Java.registerClass({ name: 'com.evil.WebAppInterface', fields: { mContext: 'android.content.Context', }, methods: { $init: [{ argumentTypes: ['android.content.Context'], implementation(context) { console.log("Initializing", context); this.mContext.value = context; } }], // Example export showToast: [{ returnType: 'void', argumentTypes: ['java.lang.String'], implementation(message) { const Toast = Java.use('android.widget.Toast'); // console.log(this.mContext.value, message, Toast.LENGTH_SHORT.value); Toast.makeText.overload('android.content.Context', 'java.lang.CharSequence', 'int').call(Toast, this.mContext.value, message.toString(), Toast.LENGTH_SHORT.value).show(); } }] } }); // Hook into the main activity to get the context const Activity = Java.use('android.app.Activity'); Activity.onCreate.overload('android.os.Bundle').implementation = function(savedInstanceState) { // Call the super this.onCreate(savedInstanceState); // Access the context const context = this; console.log('Context:', context); const webappinterface = WebAppInterface.$new(context); // Hook loadUrl calls, to dynamically add our JavaScript environment WebView.loadUrl.overload('java.lang.String').implementation = function (url) { console.log('Adding JavaScript interface to webview, navigating to:', url); this.addJavascriptInterface(webappinterface, "AndroidInterface"); return this.loadUrl(url); } }; // Intercepting calls to WebViews to instruct the existince of @JavascriptInterface const Executable = Java.use('java.lang.reflect.Executable'); Executable.isAnnotationPresent.implementation = function (clazz) { const name = clazz.getName(); console.log('Class:', name); if (name === "android.webkit.JavascriptInterface") { console.log("Overriding; Instruct code the annotation IS there"); return true; } return this.isAnnotationPresent(clazz); } });