[add] Linking: event listeners

Fix ##1650
Close #1863
This commit is contained in:
Sudhanshu Gautam
2021-01-04 21:39:15 +05:30
committed by Nicolas Gallagher
parent 5e222dbbd5
commit e493af50cf
3 changed files with 96 additions and 9 deletions

View File

@@ -9,6 +9,14 @@ Linking gives you a general interface for securely opening external URLs from Ja
## Methods
### addEventListener(event, callback)
Adds a event listener for the specified event. The callback will be called when the said event is dispatched.
### removeEventListener(event, callback)
Removes a previously added event listener for the specified event. The callback must be the same object as the one passed to `addEventListener`.
### canOpenURL(url)
Returns a `Promise` that resolves to a boolean indicating whether the app can open the URL.
@@ -23,9 +31,23 @@ Try to open the given url in a secure fashion. The method returns a `Promise`
object. If the url opens, the promise is resolved. If not, the promise is
rejected.
> On opening URL successfully, dispatches the `onOpen` event.
## Events
### `onOpen`
Dispatched when a call to `Linking.openURL` succeeds. Type signature of the callback is:
```js
(url: string) => void
```
## Example
<Preview withSource='none'>
> Listener added to the`onOpen` event. Check the console for the event log after a URL is opened.
<Preview withSource="none">
<Story name="openURL">
<Stories.openURL />
</Story>

View File

@@ -1,15 +1,31 @@
/**
* @flow
*/
import { Linking, StyleSheet, Text, View } from 'react-native';
import React, { PureComponent } from 'react';
const url = 'https://mathiasbynens.github.io/rel-noopener/malicious.html';
class OpenURLExample extends PureComponent {
componentDidMount() {
Linking.addEventListener('onOpen', this.onOpenURL);
}
componentWillUnmount() {
Linking.removeEventListener('onOpen', this.onOpenURL);
}
handlePress() {
Linking.canOpenURL(url).then(supported => {
return Linking.openURL(url);
});
}
onOpenURL(url: string) {
console.log(`%c opened the url: ${url} `, 'background: #D32F2F; color: #FFFFFF');
}
render() {
return (
<View>

View File

@@ -13,28 +13,77 @@ import invariant from 'fbjs/lib/invariant';
const initialURL = canUseDOM ? window.location.href : '';
const Linking = {
addEventListener() {},
removeEventListener() {},
type Callback = (...args: any) => void;
type OnOpenCallback = (event: 'onOpen', callback: (url: string) => void) => void;
type GenericCallback = (event: string, callback: Callback) => void;
class Linking {
/**
* An object mapping of event name
* and all the callbacks subscribing to it
*/
_eventCallbacks: { [key: string]: Array<Callback> } = {};
_dispatchEvent(event: string, ...data: any) {
const listeners = this._eventCallbacks[event];
if (listeners != null && Array.isArray(listeners)) {
listeners.map(listener => {
listener(...data);
});
}
}
/**
* Adds a event listener for the specified event. The callback will be called when the
* said event is dispatched.
*/
addEventListener: OnOpenCallback | GenericCallback = (event: string, callback: Callback) => {
if (!this._eventCallbacks[event]) {
this._eventCallbacks[event] = [callback];
return;
}
this._eventCallbacks[event].push(callback);
};
/**
* Removes a previously added event listener for the specified event. The callback must
* be the same object as the one passed to `addEventListener`.
*/
removeEventListener: OnOpenCallback | GenericCallback = (event: string, callback: Callback) => {
const callbacks = this._eventCallbacks[event];
const filteredCallbacks = callbacks.filter(c => c.toString() !== callback.toString());
this._eventCallbacks[event] = filteredCallbacks;
};
canOpenURL(): Promise<boolean> {
return Promise.resolve(true);
},
}
getInitialURL(): Promise<string> {
return Promise.resolve(initialURL);
},
}
/**
* Try to open the given url in a secure fashion. The method returns a Promise object.
* If the url opens, the promise is resolved. If not, the promise is rejected.
* Dispatches the `onOpen` event if `url` is opened successfully
*/
openURL(url: string): Promise<Object | void> {
try {
open(url);
this._dispatchEvent('onOpen', url);
return Promise.resolve();
} catch (e) {
return Promise.reject(e);
}
},
}
_validateURL(url: string) {
invariant(typeof url === 'string', 'Invalid URL: should be a string. Was: ' + url);
invariant(url, 'Invalid URL: cannot be empty');
}
};
}
const open = url => {
if (canUseDOM) {
@@ -42,4 +91,4 @@ const open = url => {
}
};
export default Linking;
export default (new Linking(): Linking);