Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(android)!: Moving cordova to a plugin for optional cordova #7806

Open
wants to merge 11 commits into
base: RDMR-129
Choose a base branch
from
163 changes: 87 additions & 76 deletions android/capacitor/src/main/java/com/getcapacitor/Bridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
import com.getcapacitor.android.R;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.annotation.Permission;
import com.getcapacitor.cordova.MockCordovaInterfaceImpl;
import com.getcapacitor.cordova.MockCordovaWebViewImpl;
import com.getcapacitor.util.HostMask;
import com.getcapacitor.util.InternalUtils;
import com.getcapacitor.util.PermissionHelper;
Expand All @@ -49,13 +47,9 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.cordova.ConfigXmlParser;
import org.apache.cordova.CordovaPreferences;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginEntry;
import org.apache.cordova.PluginManager;
import org.json.JSONException;

/**
Expand Down Expand Up @@ -119,9 +113,6 @@ public class Bridge {
private ArrayList<String> authorities = new ArrayList<>();
// A reference to the main WebView for the app
private final WebView webView;
public final MockCordovaInterfaceImpl cordovaInterface;
private CordovaWebView cordovaWebView;
private CordovaPreferences preferences;
private BridgeWebViewClient webViewClient;
private App app;

Expand All @@ -141,6 +132,8 @@ public class Bridge {
// A map of Plugin Id's to PluginHandle's
private Map<String, PluginHandle> plugins = new HashMap<>();

private Map<String, MessageHandler.Interceptor> interceptors = new HashMap<>();

// Stored plugin calls that we're keeping around to call again someday
private Map<String, PluginCall> savedCalls = new HashMap<>();

Expand Down Expand Up @@ -175,12 +168,12 @@ public Bridge(
AppCompatActivity context,
WebView webView,
List<Class<? extends Plugin>> initialPlugins,
MockCordovaInterfaceImpl cordovaInterface,
PluginManager pluginManager,
CordovaPreferences preferences,
Object cordovaInterface,
Object pluginManager,
Object preferences,
CapConfig config
) {
this(context, null, null, webView, initialPlugins, new ArrayList<>(), cordovaInterface, pluginManager, preferences, config);
this(context, (ServerPath) null, (Fragment) null, webView, initialPlugins, new ArrayList<>(), config);
}

private Bridge(
Expand All @@ -190,9 +183,6 @@ private Bridge(
WebView webView,
List<Class<? extends Plugin>> initialPlugins,
List<Plugin> pluginInstances,
MockCordovaInterfaceImpl cordovaInterface,
PluginManager pluginManager,
CordovaPreferences preferences,
CapConfig config
) {
this.app = new App();
Expand All @@ -203,20 +193,17 @@ private Bridge(
this.webViewClient = new BridgeWebViewClient(this);
this.initialPlugins = initialPlugins;
this.pluginInstances = pluginInstances;
this.cordovaInterface = cordovaInterface;
this.preferences = preferences;

// Start our plugin execution threads and handlers
handlerThread.start();
taskHandler = new Handler(handlerThread.getLooper());

this.config = config != null ? config : CapConfig.loadDefault(getActivity());
Logger.init(this.config);

// Initialize web view and message handler for it
this.initWebView();
this.setAllowedOriginRules();
this.msgHandler = new MessageHandler(this, webView, pluginManager);
this.msgHandler = new MessageHandler(this, webView);

// Grab any intent info that our app was launched with
Intent intent = context.getIntent();
Expand Down Expand Up @@ -432,12 +419,30 @@ private boolean isNewBinary() {
return false;
}

private Plugin cordova() {
PluginHandle handle = getPlugin("__CordovaHandle");
if (handle != null) {
return handle.getInstance();
}
return null;
}

public boolean isDeployDisabled() {
return preferences.getBoolean("DisableDeploy", false);
Plugin cordova = this.cordova();
if (cordova != null) {
return cordova.hasPermission("DisableDeploy");
} else {
return false;
}
}

public boolean shouldKeepRunning() {
return preferences.getBoolean("KeepRunning", true);
Plugin cordova = this.cordova();
if (cordova != null) {
return cordova.hasPermission("KeepRunning");
} else {
return false;
}
}

public void handleAppUrlLoadError(Exception ex) {
Expand All @@ -456,10 +461,6 @@ public boolean isDevMode() {
return (getActivity().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}

protected void setCordovaWebView(CordovaWebView cordovaWebView) {
this.cordovaWebView = cordovaWebView;
}

/**
* Get the Context for the App
* @return
Expand Down Expand Up @@ -549,6 +550,14 @@ public CapConfig getConfig() {
return this.config;
}

public MessageHandler.Interceptor getCallInterceptor(String type) {
return this.interceptors.get(type);
}

public void registerInterceptor(String type, MessageHandler.Interceptor interceptor) {
this.interceptors.put(type, interceptor);
}

public void reset() {
savedCalls = new HashMap<>();
}
Expand Down Expand Up @@ -1096,11 +1105,14 @@ boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[]
if (plugin == null) {
boolean permissionHandled = false;
Logger.debug("Unable to find a Capacitor plugin to handle permission requestCode, trying Cordova plugins " + requestCode);
try {
permissionHandled = cordovaInterface.handlePermissionResult(requestCode, permissions, grantResults);
} catch (JSONException e) {
Logger.debug("Error on Cordova plugin permissions request " + e.getMessage());
PluginHandle cordovaHandle = getPlugin("__CordovaPlugin");

if (cordovaHandle != null) {
Plugin cordovaPlugin = cordovaHandle.getInstance();
cordovaPlugin.handleRequestPermissionsResult(requestCode, permissions, grantResults);
permissionHandled = cordovaPlugin.hasDefinedRequiredPermissions();
}

return permissionHandled;
}

Expand Down Expand Up @@ -1235,7 +1247,14 @@ boolean onActivityResult(int requestCode, int resultCode, Intent data) {

if (plugin == null || plugin.getInstance() == null) {
Logger.debug("Unable to find a Capacitor plugin to handle requestCode, trying Cordova plugins " + requestCode);
return cordovaInterface.onActivityResult(requestCode, resultCode, data);
PluginHandle cordovaHandle = getPlugin("__CordovaPlugin");
if (cordovaHandle != null) {
Plugin cordovaPlugin = cordovaHandle.getInstance();
cordovaPlugin.handleOnActivityResult(requestCode, resultCode, data);
// This is our disgusting way of returning the boolean out of the cordova interface
return cordovaPlugin.hasRequiredPermissions();
}
// return cordovaInterface.onActivityResult(requestCode, resultCode, data);
}

// deprecated, to be removed
Expand Down Expand Up @@ -1265,10 +1284,6 @@ public void onNewIntent(Intent intent) {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnNewIntent(intent);
}

if (cordovaWebView != null) {
cordovaWebView.onNewIntent(intent);
}
}

/**
Expand Down Expand Up @@ -1297,10 +1312,6 @@ public void onStart() {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnStart();
}

if (cordovaWebView != null) {
cordovaWebView.handleStart();
}
}

/**
Expand All @@ -1310,10 +1321,6 @@ public void onResume() {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnResume();
}

if (cordovaWebView != null) {
cordovaWebView.handleResume(this.shouldKeepRunning());
}
}

/**
Expand All @@ -1323,11 +1330,6 @@ public void onPause() {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnPause();
}

if (cordovaWebView != null) {
boolean keepRunning = this.shouldKeepRunning() || cordovaInterface.getActivityResultCallback() != null;
cordovaWebView.handlePause(keepRunning);
}
}

/**
Expand All @@ -1337,10 +1339,6 @@ public void onStop() {
for (PluginHandle plugin : plugins.values()) {
plugin.getInstance().handleOnStop();
}

if (cordovaWebView != null) {
cordovaWebView.handleStop();
}
}

/**
Expand All @@ -1352,10 +1350,6 @@ public void onDestroy() {
}

handlerThread.quitSafely();

if (cordovaWebView != null) {
cordovaWebView.handleDestroy();
}
}

/**
Expand Down Expand Up @@ -1542,22 +1536,7 @@ public Builder setServerPath(ServerPath serverPath) {

public Bridge create() {
// Cordova initialization
ConfigXmlParser parser = new ConfigXmlParser();
parser.parse(activity.getApplicationContext());
CordovaPreferences preferences = parser.getPreferences();
preferences.setPreferencesBundle(activity.getIntent().getExtras());
List<PluginEntry> pluginEntries = parser.getPluginEntries();

MockCordovaInterfaceImpl cordovaInterface = new MockCordovaInterfaceImpl(activity);
if (instanceState != null) {
cordovaInterface.restoreInstanceState(instanceState);
}

WebView webView = this.fragment != null ? fragment.getView().findViewById(R.id.webview) : activity.findViewById(R.id.webview);
MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(activity.getApplicationContext());
mockWebView.init(cordovaInterface, pluginEntries, preferences, webView);
PluginManager pluginManager = mockWebView.getPluginManager();
cordovaInterface.onCordovaInit(pluginManager);

// Bridge initialization
Bridge bridge = new Bridge(
Expand All @@ -1567,9 +1546,9 @@ public Bridge create() {
webView,
plugins,
pluginInstances,
cordovaInterface,
pluginManager,
preferences,
// cordovaInterface,
// pluginManager,
// preferences,
config
);

Expand All @@ -1578,14 +1557,46 @@ public Bridge create() {
capacitorWebView.setBridge(bridge);
}

bridge.setCordovaWebView(mockWebView);
// bridge.setCordovaWebView(mockWebView);
bridge.setWebViewListeners(webViewListeners);
bridge.setRouteProcessor(routeProcessor);

if (instanceState != null) {
PluginHandle maybeCordova = bridge.getPlugin("__CordovaPlugin");
if (maybeCordova != null) {
maybeCordova.getInstance().restoreState(instanceState);
}
bridge.restoreInstanceState(instanceState);
}

bridge.registerInterceptor("message", postData -> {
try {
String callbackId = postData.getString("callbackId");
String pluginId = postData.getString("pluginId");
String methodName = postData.getString("methodName");
JSObject methodData = postData.getJSObject("options", new JSObject());

Logger.verbose(
Logger.tags("Plugin"),
"To native (Capacitor plugin): callbackId: " +
callbackId +
", pluginId: " +
pluginId +
", methodName: " +
methodName
);

PluginCall call = new PluginCall(bridge.msgHandler, pluginId, callbackId, methodName, methodData);
bridge.callPluginMethod(pluginId, methodName, call);
} catch (JSONException e) {
Logger.error(e.getMessage());
}
});

bridge.registerInterceptor("js.error", postData -> {
Logger.error("JavaScript Error: " + postData.toString());
});

return bridge;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ protected void onCreate(Bundle savedInstanceState) {
return;
}

PluginManager loader = new PluginManager(getAssets());
// TODO: Undo this
PluginLoader loader = new PluginLoader(getAssets());

try {
bridgeBuilder.addPlugins(loader.loadPluginClasses());
Expand Down
Loading
Loading