diff --git a/android/capacitor/src/main/java/com/getcapacitor/App.java b/android/capacitor/src/main/java/com/getcapacitor/App.java new file mode 100644 index 000000000..9b12dfa52 --- /dev/null +++ b/android/capacitor/src/main/java/com/getcapacitor/App.java @@ -0,0 +1,89 @@ +package com.getcapacitor; + +import androidx.annotation.Nullable; + +public class App { + + /** + * Interface for callbacks when app status changes. + */ + public interface AppStatusChangeListener { + void onAppStatusChanged(Boolean isActive); + } + + /** + * Interface for callbacks when back button is pressed. + */ + public interface BackButtonListener { + void onBackButton(); + } + + /** + * Interface for callbacks when app is restored with pending plugin call. + */ + public interface AppRestoredListener { + void onAppRestored(PluginResult result); + } + + @Nullable + private AppStatusChangeListener statusChangeListener; + + @Nullable + private BackButtonListener backButtonListener; + + @Nullable + private AppRestoredListener appRestoredListener; + + private boolean isActive = false; + + public boolean isActive() { + return isActive; + } + + /** + * Set the object to receive callbacks. + * @param listener + */ + public void setStatusChangeListener(@Nullable AppStatusChangeListener listener) { + this.statusChangeListener = listener; + } + + /** + * Set the object to receive callbacks. + * @param listener + */ + public void setBackButtonListener(@Nullable BackButtonListener listener) { + this.backButtonListener = listener; + } + + /** + * Set the object to receive callbacks. + * @param listener + */ + public void setAppRestoredListener(@Nullable AppRestoredListener listener) { + this.appRestoredListener = listener; + } + + protected void fireRestoredResult(PluginResult result) { + if (appRestoredListener != null) { + appRestoredListener.onAppRestored(result); + } + } + + public void fireStatusChange(boolean isActive) { + this.isActive = isActive; + if (statusChangeListener != null) { + statusChangeListener.onAppStatusChanged(isActive); + } + } + + public void fireBackButton() { + if (backButtonListener != null) { + backButtonListener.onBackButton(); + } + } + + public boolean hasBackButtonListeners() { + return backButtonListener != null; + } +} diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index d722e54b4..1289b0808 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -15,7 +15,6 @@ import android.webkit.ValueCallback; import android.webkit.WebSettings; import android.webkit.WebView; -import com.getcapacitor.plugin.App; import com.getcapacitor.plugin.Geolocation; import com.getcapacitor.plugin.LocalNotifications; import com.getcapacitor.plugin.PushNotifications; @@ -83,6 +82,7 @@ public class Bridge { public final CordovaInterfaceImpl cordovaInterface; private CordovaPreferences preferences; private BridgeWebViewClient webViewClient; + private App app; // Our MessageHandler for sending and receiving data to the WebView private final MessageHandler msgHandler; @@ -123,6 +123,7 @@ public Bridge( CordovaPreferences preferences, JSONObject config ) { + this.app = new App(); this.context = context; this.webView = webView; this.webViewClient = new BridgeWebViewClient(this); @@ -157,6 +158,10 @@ public Bridge( this.loadWebView(); } + public App getApp() { + return app; + } + private void loadWebView() { appUrlConfig = this.config.getString("server.url"); String[] appAllowNavigationConfig = this.config.getArray("server.allowNavigation"); @@ -379,7 +384,6 @@ private void initWebView() { * Register our core Plugin APIs */ private void registerAllPlugins() { - this.registerPlugin(App.class); this.registerPlugin(BackgroundTask.class); this.registerPlugin(LocalNotifications.class); this.registerPlugin(Geolocation.class); @@ -617,12 +621,6 @@ private JSInjector getJSInjector() { return null; } - protected void storeDanglingPluginResult(PluginCall call, PluginResult result) { - PluginHandle appHandle = getPlugin("App"); - App appPlugin = (App) appHandle.getInstance(); - appPlugin.fireRestoredResult(result); - } - /** * Restore any saved bundle state data * @param savedInstanceState @@ -805,18 +803,14 @@ public void onDestroy() { } public void onBackPressed() { - PluginHandle appHandle = getPlugin("App"); - if (appHandle != null) { - App appPlugin = (App) appHandle.getInstance(); - - // If there are listeners, don't do the default action, as this means the user - // wants to override the back button - if (appPlugin.hasBackButtonListeners()) { - appPlugin.fireBackButton(); - } else { - if (webView.canGoBack()) { - webView.goBack(); - } + // If there are listeners, don't do the default action, as this means the user + // wants to override the back button + if (app.hasBackButtonListeners()) { + app.fireBackButton(); + triggerJSEvent("backbutton", "document"); + } else { + if (webView.canGoBack()) { + webView.goBack(); } } } diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java index 9d7485133..953371b5f 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java @@ -9,7 +9,6 @@ import com.getcapacitor.android.R; import com.getcapacitor.cordova.MockCordovaInterfaceImpl; import com.getcapacitor.cordova.MockCordovaWebViewImpl; -import com.getcapacitor.plugin.App; import java.util.ArrayList; import java.util.List; import org.apache.cordova.ConfigXmlParser; @@ -90,22 +89,6 @@ public Bridge getBridge() { return this.bridge; } - /** - * Notify the App plugin that the current state changed - * @param isActive - */ - private void fireAppStateChanged(boolean isActive) { - PluginHandle handle = bridge.getPlugin("App"); - if (handle == null) { - return; - } - - App appState = (App) handle.getInstance(); - if (appState != null) { - appState.fireChange(isActive); - } - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -135,7 +118,7 @@ public void onRestart() { public void onResume() { super.onResume(); - fireAppStateChanged(true); + bridge.getApp().fireStatusChange(true); this.bridge.onResume(); @@ -163,7 +146,7 @@ public void onStop() { activityDepth = Math.max(0, activityDepth - 1); if (activityDepth == 0) { - fireAppStateChanged(false); + bridge.getApp().fireStatusChange(false); } this.bridge.onStop(); diff --git a/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java b/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java index 3a25341b3..50f83897d 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java +++ b/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java @@ -104,7 +104,7 @@ public void sendResponseMessage(PluginCall call, PluginResult successResult, Plu final WebView webView = this.webView; webView.post(() -> webView.evaluateJavascript(runScript, null)); } else { - bridge.storeDanglingPluginResult(call, data); + bridge.getApp().fireRestoredResult(data); } } catch (Exception ex) { Logger.error("sendResponseMessage: error: " + ex); diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/App.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/App.java deleted file mode 100644 index 2426952f1..000000000 --- a/android/capacitor/src/main/java/com/getcapacitor/plugin/App.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.getcapacitor.plugin; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; -import com.getcapacitor.JSObject; -import com.getcapacitor.Logger; -import com.getcapacitor.NativePlugin; -import com.getcapacitor.Plugin; -import com.getcapacitor.PluginCall; -import com.getcapacitor.PluginMethod; -import com.getcapacitor.PluginResult; - -@NativePlugin -public class App extends Plugin { - - private static final String EVENT_BACK_BUTTON = "backButton"; - private static final String EVENT_URL_OPEN = "appUrlOpen"; - private static final String EVENT_STATE_CHANGE = "appStateChange"; - private static final String EVENT_RESTORED_RESULT = "appRestoredResult"; - private boolean isActive = false; - - public void fireChange(boolean isActive) { - Logger.debug(getLogTag(), "Firing change: " + isActive); - JSObject data = new JSObject(); - data.put("isActive", isActive); - this.isActive = isActive; - notifyListeners(EVENT_STATE_CHANGE, data, false); - } - - public void fireRestoredResult(PluginResult result) { - Logger.debug(getLogTag(), "Firing restored result"); - notifyListeners(EVENT_RESTORED_RESULT, result.getWrappedResult(), true); - } - - public void fireBackButton() { - notifyListeners(EVENT_BACK_BUTTON, new JSObject(), true); - - // For Cordova compat, emit the backbutton event - bridge.triggerJSEvent("backbutton", "document"); - } - - public boolean hasBackButtonListeners() { - return hasListeners(EVENT_BACK_BUTTON); - } - - @PluginMethod - public void exitApp(PluginCall call) { - getBridge().getActivity().finish(); - } - - @PluginMethod - public void getLaunchUrl(PluginCall call) { - Uri launchUri = bridge.getIntentUri(); - if (launchUri != null) { - JSObject d = new JSObject(); - d.put("url", launchUri.toString()); - call.success(d); - } else { - call.success(); - } - } - - @PluginMethod - public void getState(PluginCall call) { - JSObject data = new JSObject(); - data.put("isActive", this.isActive); - call.success(data); - } - - @PluginMethod - public void canOpenUrl(PluginCall call) { - String url = call.getString("url"); - if (url == null) { - call.error("Must supply a url"); - return; - } - - Context ctx = this.getActivity().getApplicationContext(); - final PackageManager pm = ctx.getPackageManager(); - - JSObject ret = new JSObject(); - try { - pm.getPackageInfo(url, PackageManager.GET_ACTIVITIES); - ret.put("value", true); - call.success(ret); - return; - } catch (PackageManager.NameNotFoundException e) { - Logger.error(getLogTag(), "Package name '" + url + "' not found!", null); - } - - ret.put("value", false); - call.success(ret); - } - - @PluginMethod - public void openUrl(PluginCall call) { - String url = call.getString("url"); - if (url == null) { - call.error("Must provide a url to open"); - return; - } - - JSObject ret = new JSObject(); - final PackageManager manager = getContext().getPackageManager(); - Intent launchIntent = new Intent(Intent.ACTION_VIEW); - launchIntent.setData(Uri.parse(url)); - - try { - getActivity().startActivity(launchIntent); - ret.put("completed", true); - } catch (Exception ex) { - launchIntent = manager.getLaunchIntentForPackage(url); - try { - getActivity().startActivity(launchIntent); - ret.put("completed", true); - } catch (Exception expgk) { - ret.put("completed", false); - } - } - call.success(ret); - } - - /** - * Handle ACTION_VIEW intents to store a URL that was used to open the app - * @param intent - */ - @Override - protected void handleOnNewIntent(Intent intent) { - super.handleOnNewIntent(intent); - - final String intentString = intent.getDataString(); - - // read intent - String action = intent.getAction(); - Uri url = intent.getData(); - - if (!Intent.ACTION_VIEW.equals(action) || url == null) { - return; - } - - JSObject ret = new JSObject(); - ret.put("url", url.toString()); - notifyListeners(EVENT_URL_OPEN, ret, true); - } -} diff --git a/core/src/core-plugin-definitions.ts b/core/src/core-plugin-definitions.ts index 70e1e4652..79f215443 100644 --- a/core/src/core-plugin-definitions.ts +++ b/core/src/core-plugin-definitions.ts @@ -2,7 +2,6 @@ import { Plugin, PluginListenerHandle } from './definitions'; export interface PluginRegistry { - App: AppPlugin; BackgroundTask: BackgroundTaskPlugin; Geolocation: GeolocationPlugin; LocalNotifications: LocalNotificationsPlugin; @@ -29,133 +28,6 @@ export interface CancellableCallback { */ cancel: Function; } -// - -export interface AppPlugin extends Plugin { - /** - * Force exit the app. This should only be used in conjunction with the `backButton` handler for Android to - * exit the app when navigation is complete. - * - * Ionic handles this itself so you shouldn't need to call this if using Ionic - */ - exitApp(): never; - /** - * Check if an app can be opened with the given URL - */ - canOpenUrl(options: { url: string }): Promise<{ value: boolean }>; - - /** - * Open an app with the given URL - */ - openUrl(options: { url: string }): Promise<{ completed: boolean }>; - - /** - * Gets the current app state - */ - getState(): Promise; - - /** - * Get the URL the app was launched with, if any - */ - getLaunchUrl(): Promise; - - /** - * Listen for changes in the App's active state (whether the app is in the foreground or background) - */ - addListener( - eventName: 'appStateChange', - listenerFunc: (state: AppState) => void, - ): PluginListenerHandle; - - /** - * Listen for url open events for the app. This handles both custom URL scheme links as well - * as URLs your app handles (Universal Links on iOS and App Links on Android) - */ - addListener( - eventName: 'appUrlOpen', - listenerFunc: (data: AppUrlOpen) => void, - ): PluginListenerHandle; - - /** - * If the app was launched with previously persisted plugin call data, such as on Android - * when an activity returns to an app that was closed, this call will return any data - * the app was launched with, converted into the form of a result from a plugin call. - */ - addListener( - eventName: 'appRestoredResult', - listenerFunc: (data: AppRestoredResult) => void, - ): PluginListenerHandle; - - /** - * Listen for the hardware back button event (Android only). Listening for this event will disable the - * default back button behaviour, so you might want to call `window.history.back()` manually. - * If you want to close the app, call `App.exitApp()`. - */ - addListener( - eventName: 'backButton', - listenerFunc: (data: BackButtonResult) => void, - ): PluginListenerHandle; - - /** - * Remove all native listeners for this plugin - */ - removeAllListeners(): void; -} - -export interface BackButtonResult {} - -export interface AppState { - isActive: boolean; -} - -export interface AppUrlOpen { - /** - * The URL the app was opened with - */ - url: string; - - /** - * The source application opening the app (iOS only) - * https://developer.apple.com/documentation/uikit/uiapplicationopenurloptionskey/1623128-sourceapplication - */ - iosSourceApplication?: any; - /** - * Whether the app should open the passed document in-place - * or must copy it first. - * https://developer.apple.com/documentation/uikit/uiapplicationopenurloptionskey/1623123-openinplace - */ - iosOpenInPlace?: boolean; -} - -export interface AppLaunchUrl { - url: string; -} - -export interface AppRestoredResult { - /** - * The pluginId this result corresponds to. For example, `Camera`. - */ - pluginId: string; - /** - * The methodName this result corresponds to. For example, `getPhoto` - */ - methodName: string; - /** - * The result data passed from the plugin. This would be the result you'd - * expect from normally calling the plugin method. For example, `CameraPhoto` - */ - data?: any; - /** - * Boolean indicating if the plugin call succeeded - */ - success: boolean; - /** - * If the plugin call didn't succeed, it will contain the error message - */ - error?: { - message: string; - }; -} // diff --git a/core/src/web-plugins.ts b/core/src/web-plugins.ts index e99c8ab25..e15e988bb 100644 --- a/core/src/web-plugins.ts +++ b/core/src/web-plugins.ts @@ -1,15 +1,12 @@ import { mergeWebPlugin } from './plugins'; -import { App } from './web/app'; import { Geolocation } from './web/geolocation'; import { LocalNotifications } from './web/local-notifications'; import { SplashScreen } from './web/splash-screen'; -export * from './web/app'; export * from './web/geolocation'; export * from './web/local-notifications'; export * from './web/splash-screen'; -mergeWebPlugin(App); mergeWebPlugin(Geolocation); mergeWebPlugin(LocalNotifications); mergeWebPlugin(SplashScreen); diff --git a/core/src/web/app.ts b/core/src/web/app.ts deleted file mode 100644 index 611431a81..000000000 --- a/core/src/web/app.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { - AppPlugin, - AppLaunchUrl, - AppState, -} from '../core-plugin-definitions'; - -import { WebPlugin } from './index'; - -export class AppPluginWeb extends WebPlugin implements AppPlugin { - constructor() { - super({ name: 'App' }); - - if (typeof document !== 'undefined') { - document.addEventListener( - 'visibilitychange', - this.handleVisibilityChange.bind(this), - false, - ); - } - } - - exitApp(): never { - throw new Error('Method not implemented.'); - } - - canOpenUrl(_options: { url: string }): Promise<{ value: boolean }> { - return Promise.resolve({ value: true }); - } - - openUrl(_options: { url: string }): Promise<{ completed: boolean }> { - return Promise.resolve({ completed: true }); - } - - getLaunchUrl(): Promise { - return Promise.resolve({ url: '' }); - } - - getState(): Promise { - return Promise.resolve({ isActive: document.hidden !== true }); - } - - handleVisibilityChange(): void { - const data = { - isActive: document.hidden !== true, - }; - - this.notifyListeners('appStateChange', data); - } -} - -const App = new AppPluginWeb(); - -export { App }; diff --git a/ios/Capacitor/Capacitor/CAPBridge.swift b/ios/Capacitor/Capacitor/CAPBridge.swift index 92487d5ac..b68ff3dc3 100644 --- a/ios/Capacitor/Capacitor/CAPBridge.swift +++ b/ios/Capacitor/Capacitor/CAPBridge.swift @@ -40,8 +40,6 @@ enum BridgeError: Error { public var storedCalls = [String: CAPPluginCall]() // Scheme to use when serving content public var scheme: String - // Whether the app is active - private var isActive = true // Wheter to inject the Cordova files private var injectCordovaFiles = false @@ -65,7 +63,6 @@ enum BridgeError: Error { exportCoreJS(localUrl: localUrl!) registerPlugins() setupCordovaCompatibility() - bindObservers() NotificationCenter.default.addObserver(forName: CAPBridge.tmpVCAppeared.name, object: .none, queue: .none) { [weak self] _ in self?.tmpWindow = nil } @@ -187,35 +184,6 @@ enum BridgeError: Error { CAPLog.print("⚡️ ❌ Please verify your installation or file an issue") } - /** - * Bind notification center observers to watch for app active/inactive status - */ - func bindObservers() { - let appStatePlugin = getOrLoadPlugin(pluginName: "App") as? CAPAppPlugin - - NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: OperationQueue.main) { [weak self, weak appStatePlugin] (_) in - CAPLog.print("APP ACTIVE") - self?.isActive = true - if let strongSelf = self { - appStatePlugin?.fireChange(isActive: strongSelf.isActive) - } - } - NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: OperationQueue.main) { [weak self, weak appStatePlugin] (_) in - CAPLog.print("APP INACTIVE") - self?.isActive = false - if let strongSelf = self { - appStatePlugin?.fireChange(isActive: strongSelf.isActive) - } - } - } - - /** - * - Returns: whether the app is currently active - */ - func isAppActive() -> Bool { - return isActive - } - /** * Export core JavaScript to the webview */ @@ -481,32 +449,25 @@ enum BridgeError: Error { * Send a successful result to the JavaScript layer. */ public func toJs(result: JSResult, save: Bool) { - do { - let resultJson = try result.toJson() - CAPLog.print("⚡️ TO JS", resultJson.prefix(256)) - - DispatchQueue.main.async { - self.getWebView()?.evaluateJavaScript(""" - window.Capacitor.fromNative({ - callbackId: '\(result.call.callbackId)', - pluginId: '\(result.call.pluginId)', - methodName: '\(result.call.method)', - save: \(save), - success: true, - data: \(resultJson) - }) - """) { (result, error) in - if error != nil && result != nil { - CAPLog.print(result!) - } + let resultJson = result.toJson() + CAPLog.print("⚡️ TO JS", resultJson.prefix(256)) + + DispatchQueue.main.async { + self.getWebView()?.evaluateJavaScript(""" + window.Capacitor.fromNative({ + callbackId: '\(result.call.callbackId)', + pluginId: '\(result.call.pluginId)', + methodName: '\(result.call.method)', + save: \(save), + success: true, + data: \(resultJson) + }) + """) { (result, error) in + if error != nil && result != nil { + CAPLog.print(result!) } } - } catch { - if let jsError = error as? JSProcessingError, let appState = getOrLoadPlugin(pluginName: "App") as? CAPAppPlugin { - appState.firePluginError(jsError) - } } - } /** diff --git a/ios/Capacitor/Capacitor/JS.swift b/ios/Capacitor/Capacitor/JS.swift index 4709dfdb8..1678ffdc4 100644 --- a/ios/Capacitor/Capacitor/JS.swift +++ b/ios/Capacitor/Capacitor/JS.swift @@ -1,15 +1,5 @@ import Foundation -enum JSProcessingError: LocalizedError { - case jsonSerializeError(call: JSCall) - var errorDescription: String? { - switch self { - case .jsonSerializeError(call: let call): - return "Unable to JSON serialize plugin data result for plugin \(call.pluginId) and method \(call.method)" - } - } -} - public typealias JSObject = [String: Any] public typealias JSArray = [JSObject] @@ -52,7 +42,7 @@ public class JSResult { self.result = result } - public func toJson() throws -> String { + public func toJson() -> String { if let result = result { do { if JSONSerialization.isValidJSONObject(result) { @@ -63,10 +53,7 @@ public class JSResult { } else { CAPLog.print("[Capacitor Plugin Error] - \(call.pluginId) - \(call.method) - Unable to serialize plugin response as JSON." + "Ensure that all data passed to success callback from module method is JSON serializable!") - throw JSProcessingError.jsonSerializeError(call: call) } - } catch let error as JSProcessingError { - throw error } catch { CAPLog.print("Unable to serialize plugin response as JSON: \(error.localizedDescription)") } diff --git a/ios/Capacitor/Capacitor/Plugins/App.swift b/ios/Capacitor/Capacitor/Plugins/App.swift deleted file mode 100644 index 86cbaa756..000000000 --- a/ios/Capacitor/Capacitor/Plugins/App.swift +++ /dev/null @@ -1,114 +0,0 @@ -import Foundation - -@objc(CAPAppPlugin) -public class CAPAppPlugin: CAPPlugin { - var lastUrlOpenOptions: [String: Any?]? - - override public func load() { - NotificationCenter.default.addObserver(self, selector: #selector(self.handleUrlOpened(notification:)), name: Notification.Name(CAPNotifications.URLOpen.name()), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.handleUniversalLink(notification:)), name: Notification.Name(CAPNotifications.UniversalLinkOpen.name()), object: nil) - } - - @objc func handleUrlOpened(notification: NSNotification) { - guard let object = notification.object as? [String: Any?] else { - return - } - - notifyListeners("appUrlOpen", data: makeUrlOpenObject(object), retainUntilConsumed: true) - } - - @objc func handleUniversalLink(notification: NSNotification) { - guard let object = notification.object as? [String: Any?] else { - return - } - - notifyListeners("appUrlOpen", data: makeUrlOpenObject(object), retainUntilConsumed: true) - } - - func makeUrlOpenObject(_ object: [String: Any?]) -> JSObject { - guard let url = object["url"] as? NSURL else { - return [:] - } - - let options = object["options"] as? [String: Any?] ?? [:] - return [ - "url": url.absoluteString ?? "", - "iosSourceApplication": options[UIApplication.OpenURLOptionsKey.sourceApplication.rawValue] as? String ?? "", - "iosOpenInPlace": options[UIApplication.OpenURLOptionsKey.openInPlace.rawValue] as? String ?? "" - ] - } - - func firePluginError(_ jsError: JSProcessingError) { - notifyListeners("pluginError", data: [ - "message": jsError.localizedDescription - ]) - } - - public func fireChange(isActive: Bool) { - notifyListeners("appStateChange", data: [ - "isActive": isActive - ]) - } - - @objc func exitApp(_ call: CAPPluginCall) { - call.unimplemented() - } - - @objc func getLaunchUrl(_ call: CAPPluginCall) { - if let lastUrl = CAPBridge.getLastUrl() { - let urlValue = lastUrl.absoluteString - call.resolve([ - "url": urlValue - ]) - } - call.resolve() - } - - @objc func getState(_ call: CAPPluginCall) { - DispatchQueue.main.async { - call.resolve([ - "isActive": UIApplication.shared.applicationState == UIApplication.State.active - ]) - } - } - - @objc func canOpenUrl(_ call: CAPPluginCall) { - guard let urlString = call.getString("url") else { - call.error("Must supply a URL") - return - } - - guard let url = URL.init(string: urlString) else { - call.error("Invalid URL") - return - } - - DispatchQueue.main.async { - let canOpen = UIApplication.shared.canOpenURL(url) - - call.success([ - "value": canOpen - ]) - } - } - - @objc func openUrl(_ call: CAPPluginCall) { - guard let urlString = call.getString("url") else { - call.error("Must supply a URL") - return - } - - guard let url = URL.init(string: urlString) else { - call.error("Invalid URL") - return - } - - DispatchQueue.main.async { - UIApplication.shared.open(url, options: [:]) { (completed) in - call.success([ - "completed": completed - ]) - } - } - } -} diff --git a/ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m b/ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m index 716f830ae..d6e93b5b5 100644 --- a/ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m +++ b/ios/Capacitor/Capacitor/Plugins/DefaultPlugins.m @@ -2,15 +2,6 @@ #import "CAPBridgedPlugin.h" -CAP_PLUGIN(CAPAppPlugin, "App", - CAP_PLUGIN_METHOD(exitApp, CAPPluginReturnNone); - CAP_PLUGIN_METHOD(getLaunchUrl, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(getState, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(canOpenUrl, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(openUrl, CAPPluginReturnPromise); - CAP_PLUGIN_METHOD(removeAllListeners, CAPPluginReturnNone); -) - CAP_PLUGIN(CAPBackgroundTaskPlugin, "BackgroundTask", CAP_PLUGIN_METHOD(beforeExit, CAPPluginReturnCallback); CAP_PLUGIN_METHOD(finish, CAPPluginReturnNone);