Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 55 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ npx cap sync
* [`removeAllListeners()`](#removealllisteners)
* [`addListener('browserClosed' | 'browserPageLoaded', ...)`](#addlistenerbrowserclosed--browserpageloaded-)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)
* [Enums](#enums)

</docgen-index>
Expand All @@ -45,26 +44,25 @@ openInWebView(url: string, options: WebViewOptions) => void
### openInSystemBrowser(...)

```typescript
openInSystemBrowser(url: string, options: SystemBrowserOptions) => void
openInSystemBrowser(model: OpenInSystemBrowserParameterModel) => void
```

| Param | Type |
| ------------- | --------------------------------------------------------------------- |
| **`url`** | <code>string</code> |
| **`options`** | <code><a href="#systembrowseroptions">SystemBrowserOptions</a></code> |
| Param | Type |
| ----------- | ----------------------------------------------------------------------------------------------- |
| **`model`** | <code><a href="#openinsystembrowserparametermodel">OpenInSystemBrowserParameterModel</a></code> |

--------------------


### openInExternalBrowser(...)

```typescript
openInExternalBrowser(model: OpenInExternalBrowserParameterModel) => void
openInExternalBrowser(model: OpenInDefaultParameterModel) => void
```

| Param | Type |
| ----------- | --------------------------------------------------------------------------------------------------- |
| **`model`** | <code><a href="#openinexternalbrowserparametermodel">OpenInExternalBrowserParameterModel</a></code> |
| Param | Type |
| ----------- | ----------------------------------------------------------------------------------- |
| **`model`** | <code><a href="#openindefaultparametermodel">OpenInDefaultParameterModel</a></code> |

--------------------

Expand Down Expand Up @@ -108,15 +106,19 @@ addListener(eventName: 'browserClosed' | 'browserPageLoaded', listenerFunc: () =

#### WebViewOptions

| Prop | Type |
| --------------------- | ----------------------------------------------------------------------- |
| **`showURL`** | <code>boolean</code> |
| **`showToolBar`** | <code>boolean</code> |
| **`closeButtonText`** | <code>string</code> |
| **`toolbarPosition`** | <code><a href="#toolbarposition">ToolbarPosition</a></code> |
| **`leftToRight`** | <code>boolean</code> |
| **`android`** | <code><a href="#androidwebviewoptions">AndroidWebViewOptions</a></code> |
| **`iOS`** | <code><a href="#ioswebviewoptions">iOSWebViewOptions</a></code> |
| Prop | Type |
| ------------------------------------- | ----------------------------------------------------------------------- |
| **`showURL`** | <code>boolean</code> |
| **`showToolbar`** | <code>boolean</code> |
| **`clearCache`** | <code>boolean</code> |
| **`clearSessionCache`** | <code>boolean</code> |
| **`mediaPlaybackRequiresUserAction`** | <code>boolean</code> |
| **`closeButtonText`** | <code>string</code> |
| **`toolbarPosition`** | <code><a href="#toolbarposition">ToolbarPosition</a></code> |
| **`showNavigationButtons`** | <code>boolean</code> |
| **`leftToRight`** | <code>boolean</code> |
| **`android`** | <code><a href="#androidwebviewoptions">AndroidWebViewOptions</a></code> |
| **`iOS`** | <code><a href="#ioswebviewoptions">iOSWebViewOptions</a></code> |


#### AndroidWebViewOptions
Expand All @@ -136,18 +138,26 @@ addListener(eventName: 'browserClosed' | 'browserPageLoaded', listenerFunc: () =
| **`enableViewportScale`** | <code>boolean</code> |
| **`allowInLineMediaPlayback`** | <code>boolean</code> |
| **`keyboardDisplayRequiresUserAction`** | <code>boolean</code> |
| **`surpressedIncrementalRendering`** | <code>boolean</code> |
| **`surpressIncrementalRendering`** | <code>boolean</code> |
| **`viewStyle`** | <code><a href="#iosviewstyle">iOSViewStyle</a></code> |
| **`animationEffect`** | <code><a href="#iosanimation">iOSAnimation</a></code> |
| **`animation`** | <code><a href="#iosanimation">iOSAnimation</a></code> |


#### OpenInSystemBrowserParameterModel

Defines the options for opening a URL in the syste, browser.

| Prop | Type |
| ------------- | --------------------------------------------------------------------- |
| **`options`** | <code><a href="#systembrowseroptions">SystemBrowserOptions</a></code> |


#### SystemBrowserOptions

| Prop | Type |
| ---------------- | ----------------------------------------------------------------------------------- |
| **`showURLBar`** | <code>boolean</code> |
| **`android`** | <code><a href="#androidsystembrowseroptions">AndroidSystemBrowserOptions</a></code> |
| **`iOS`** | <code><a href="#iossystembrowseroptions">iOSSystemBrowserOptions</a></code> |
| Prop | Type |
| ------------- | ----------------------------------------------------------------------------------- |
| **`android`** | <code><a href="#androidsystembrowseroptions">AndroidSystemBrowserOptions</a></code> |
| **`iOS`** | <code><a href="#iossystembrowseroptions">iOSSystemBrowserOptions</a></code> |


#### AndroidSystemBrowserOptions
Expand All @@ -164,10 +174,10 @@ addListener(eventName: 'browserClosed' | 'browserPageLoaded', listenerFunc: () =

#### AndroidBottomSheet

| Prop | Type |
| ------------- | ------------------- |
| **`height`** | <code>number</code> |
| **`isFixed`** | <code>number</code> |
| Prop | Type |
| ------------- | -------------------- |
| **`height`** | <code>number</code> |
| **`isFixed`** | <code>boolean</code> |


#### iOSSystemBrowserOptions
Expand All @@ -181,21 +191,20 @@ addListener(eventName: 'browserClosed' | 'browserPageLoaded', listenerFunc: () =
| **`enableReadersMode`** | <code>boolean</code> |


#### PluginListenerHandle

| Prop | Type |
| ------------ | ----------------------------------------- |
| **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |

#### OpenInDefaultParameterModel

### Type Aliases
Defines the options for opening a URL in the external browser and used by the others.

| Prop | Type |
| --------- | ------------------- |
| **`url`** | <code>string</code> |

#### OpenInExternalBrowserParameterModel

Defines the options for opening a URL in the external browser.
#### PluginListenerHandle

<code>{ url: string; }</code>
| Prop | Type |
| ------------ | ----------------------------------------- |
| **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |


### Enums
Expand Down Expand Up @@ -237,20 +246,12 @@ Defines the options for opening a URL in the external browser.

#### AndroidAnimation

| Members |
| ---------------------------------------- |
| **`FADE_IN`** |
| **`FADE_OUT`** |
| **`LINEAR_INTERPOLATION`** |
| **`ACCELERATE_DECELERATE_INTERPOLATOR`** |
| **`ACCELERATE_INTERPOLATOR`** |
| **`ANTICIPATE_INTERPOLATOR`** |
| **`ANTICIPATE_OVERSHOOT_INTERPOLATOR`** |
| **`BOUNCE_INTERPOLATOR`** |
| **`DECELERATE_INTERPOLATOR`** |
| **`OVERSHOOT_INTERPOLATOR`** |
| **`SLIDE_IN_LEFT`** |
| **`SLIDE_OUT_RIGHT`** |
| Members |
| --------------------- |
| **`FADE_IN`** |
| **`FADE_OUT`** |
| **`SLIDE_IN_LEFT`** |
| **`SLIDE_OUT_RIGHT`** |


#### DismissStyle
Expand Down
35 changes: 34 additions & 1 deletion example-app/src/pages/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IonButton, IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
import { InAppBrowser } from '@capacitor/os-inappbrowser';
import { InAppBrowser, SystemBrowserOptions, DefaultSystemBrowserOptions, DefaultAndroidSystemBrowserOptions, DismissStyle, iOSViewStyle, iOSAnimation } from '@capacitor/os-inappbrowser';
import './Home.css';

const Home: React.FC = () => {
Expand All @@ -10,6 +10,37 @@ const Home: React.FC = () => {
});
}

const openInSystemBrowserWithDefaults = () => {
InAppBrowser.openInSystemBrowser({
url: "https://www.google.com",
options: DefaultSystemBrowserOptions
});
}

const openInSystemBrowserWithCustomValues = () => {
InAppBrowser.openInSystemBrowser({
url: "https://www.asymco.com/",
options: {
android: DefaultAndroidSystemBrowserOptions,
iOS: {
closeButtonText: DismissStyle.CANCEL,
viewStyle: iOSViewStyle.FORM_SHEET,
animationEffect: iOSAnimation.FLIP_HORIZONTAL,
enableBarsCollapsing: false,
enableReadersMode: true
}
}
});
}

InAppBrowser.addListener('browserClosed', () => {
console.log("browser was closed.");
});

InAppBrowser.addListener('browserPageLoaded', () => {
console.log("browser was loaded.");
});

return (
<IonPage>
<IonHeader>
Expand All @@ -25,6 +56,8 @@ const Home: React.FC = () => {
</IonHeader>
<div>
<IonButton onClick={test}>TEST</IonButton>
<IonButton onClick={openInSystemBrowserWithDefaults}>System Browser with Defaults</IonButton>
<IonButton onClick={openInSystemBrowserWithCustomValues}>System Browser with Custom Values</IonButton>
</div>
</IonContent>
</IonPage>
Expand Down
111 changes: 101 additions & 10 deletions ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,123 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
public let identifier = "InAppBrowserPlugin"
public let jsName = "InAppBrowser"
public let pluginMethods: [CAPPluginMethod] = [
CAPPluginMethod(name: "openInExternalBrowser", returnType: CAPPluginReturnPromise)
.init(name: "openInExternalBrowser", returnType: CAPPluginReturnPromise),
.init(name: "openInSystemBrowser", returnType: CAPPluginReturnPromise)
]

private var plugin: OSIABEngine?
private var plugin: OSIABEngine<OSIABApplicationRouterAdapter, OSIABSafariViewControllerRouterAdapter>?
private var currentlyOpenedBrowser: (any OSIABRouter)?

override public func load() {
self.plugin = .init(application: .shared)
self.plugin = .init()
}

@objc func openInExternalBrowser(_ call: CAPPluginCall) {
if self.plugin == nil {
if self.plugin == nil {
self.load()
}

guard let plugin else {
return call.reject("Capacitor bridge is not initialized.")
return self.error(call, type: .bridgeNotInitialised)
}

let target = OSInAppBrowserTarget.openInExternalBrowser

func delegateExternalBrowser(_ url: String) {
DispatchQueue.main.async {
plugin.openExternalBrowser(url, { [weak self] success in
guard let self else { return }

if success {
self.success(call)
} else {
self.error(call, type: .failedToOpen(url: url, onTarget: target))
}
})
}
}

guard let url = call.getString("url") else {
return call.reject("The input parameters for 'openInExternalBrowser' are invalid.")
return self.error(call, type: .inputArgumentsIssue(target: target))
}

if plugin.openExternalBrowser(url) == true {
call.resolve()
} else {
call.reject("Couldn't open '\(url)' using Safari.")
delegateExternalBrowser(url)
}

@objc func openInSystemBrowser(_ call: CAPPluginCall) {
if self.plugin == nil {
self.load()
}

guard let plugin else {
return self.error(call, type: .bridgeNotInitialised)
}

let target = OSInAppBrowserTarget.openInSystemBrowser

func delegateSystemBrowser(_ url: String, _ options: OSIABSystemBrowserOptions) {
DispatchQueue.main.async {
self.currentlyOpenedBrowser = plugin.openSystemBrowser(url, options, { [weak self] event, safariViewController in
guard let self else { return }

if let event {
self.notifyListeners(event.rawValue, data: nil)
} else if let safariViewController {
self.bridge?.viewController?.show(safariViewController, sender: nil)
self.success(call)
} else {
self.error(call, type: .failedToOpen(url: url, onTarget: target))
}
})
}
}

guard let url = call.getString("url"),
let options: OSInAppBrowserInputArgumentsSystemBrowserModel = self.createModel(for: call.getObject("options"))
else { return self.error(call, type: .inputArgumentsIssue(target: target)) }

delegateSystemBrowser(url, options.toSystemBrowserOptions())
}
}

private extension InAppBrowserPlugin {
func createModel<T: Decodable>(for inputArgument: JSObject?) -> T? {
guard let argumentsDictionary = inputArgument,
let argumentsData = try? JSONSerialization.data(withJSONObject: argumentsDictionary),
let argumentsModel = try? JSONDecoder().decode(T.self, from: argumentsData)
else { return nil }
return argumentsModel
}

func success(_ call: CAPPluginCall) {
call.resolve()
}

func error(_ call: CAPPluginCall, type errorType: OSInAppBrowserError) {
call.reject(errorType.description)
}
}

private extension OSIABEngine where ExternalBrowser == OSIABApplicationRouterAdapter {
func openExternalBrowser(_ url: String, _ completionHandler: @escaping (Bool) -> Void) {
let router = OSIABApplicationRouterAdapter(UIApplication.shared)
self.openExternalBrowser(url, routerDelegate: router, completionHandler)
}
}

private extension OSIABEngine where SystemBrowser == OSIABSafariViewControllerRouterAdapter {
func openSystemBrowser(_ url: String, _ options: OSIABSystemBrowserOptions, _ completionHandler: @escaping (OSIABEventType?, UIViewController?) -> Void) -> SystemBrowser {
let router = OSIABSafariViewControllerRouterAdapter(
options,
onBrowserPageLoad: { completionHandler(.pageLoadCompleted, nil) },
onBrowserClosed: { completionHandler(.pageClosed, nil) }
)
self.openSystemBrowser(url, routerDelegate: router) { completionHandler(nil, $0) }
return router
}
}

enum OSIABEventType: String {
case pageClosed = "browserClosed"
case pageLoadCompleted = "browserPageLoaded"
}
Loading