diff --git a/app/components/client_upgrade_listener/client_upgrade_listener.js b/app/components/client_upgrade_listener/client_upgrade_listener.js
index 5013971bd..7f154608a 100644
--- a/app/components/client_upgrade_listener/client_upgrade_listener.js
+++ b/app/components/client_upgrade_listener/client_upgrade_listener.js
@@ -117,7 +117,11 @@ export default class ClientUpgradeListener extends PureComponent {
const {downloadLink} = this.props;
const {intl} = this.context;
- Linking.openURL(downloadLink).catch(() => {
+ Linking.canOpenURL(downloadLink).then((supported) => {
+ if (supported) {
+ return Linking.openURL(downloadLink);
+ }
+
Alert.alert(
intl.formatMessage({
id: 'mobile.client_upgrade.download_error.title',
@@ -128,6 +132,8 @@ export default class ClientUpgradeListener extends PureComponent {
defaultMessage: 'An error occurred while trying to open the download link.',
}),
);
+
+ return false;
});
this.toggleUpgradeMessage(false);
diff --git a/app/components/markdown/markdown_image/markdown_image.js b/app/components/markdown/markdown_image/markdown_image.js
index 0b5a1e38e..e2317234e 100644
--- a/app/components/markdown/markdown_image/markdown_image.js
+++ b/app/components/markdown/markdown_image/markdown_image.js
@@ -5,7 +5,6 @@ import PropTypes from 'prop-types';
import React from 'react';
import {intlShape} from 'react-intl';
import {
- Alert,
Linking,
Platform,
StyleSheet,
@@ -124,19 +123,11 @@ export default class MarkdownImage extends ImageViewPort {
handleLinkPress = () => {
const url = normalizeProtocol(this.props.linkDestination);
- const {intl} = this.context;
- Linking.openURL(url).catch(() => {
- Alert.alert(
- intl.formatMessage({
- id: 'mobile.link.error.title',
- defaultMessage: 'Error',
- }),
- intl.formatMessage({
- id: 'mobile.link.error.text',
- defaultMessage: 'Unable to open the link.',
- }),
- );
+ Linking.canOpenURL(url).then((supported) => {
+ if (supported) {
+ Linking.openURL(url);
+ }
});
};
diff --git a/app/components/markdown/markdown_link/markdown_link.js b/app/components/markdown/markdown_link/markdown_link.js
index 452690614..1c1f37046 100644
--- a/app/components/markdown/markdown_link/markdown_link.js
+++ b/app/components/markdown/markdown_link/markdown_link.js
@@ -64,18 +64,22 @@ export default class MarkdownLink extends PureComponent {
onPermalinkPress(match.postId, match.teamName);
}
} else {
- Linking.openURL(url).catch(() => {
- const {formatMessage} = this.context.intl;
- Alert.alert(
- formatMessage({
- id: 'mobile.server_link.error.title',
- defaultMessage: 'Link Error',
- }),
- formatMessage({
- id: 'mobile.server_link.error.text',
- defaultMessage: 'The link could not be found on this server.',
- }),
- );
+ Linking.canOpenURL(url).then((supported) => {
+ if (supported) {
+ Linking.openURL(url);
+ } else {
+ const {formatMessage} = this.context.intl;
+ Alert.alert(
+ formatMessage({
+ id: 'mobile.server_link.error.title',
+ defaultMessage: 'Link Error',
+ }),
+ formatMessage({
+ id: 'mobile.server_link.error.text',
+ defaultMessage: 'The link could not be found on this server.',
+ }),
+ );
+ }
});
}
});
diff --git a/app/components/message_attachments/attachment_author.js b/app/components/message_attachments/attachment_author.js
index 3a15361cf..c9b408a60 100644
--- a/app/components/message_attachments/attachment_author.js
+++ b/app/components/message_attachments/attachment_author.js
@@ -2,10 +2,9 @@
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
-import {Alert, Linking, Text, View} from 'react-native';
+import {Linking, Text, View} from 'react-native';
import FastImage from 'react-native-fast-image';
import PropTypes from 'prop-types';
-import {intlShape} from 'react-intl';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
@@ -17,27 +16,10 @@ export default class AttachmentAuthor extends PureComponent {
theme: PropTypes.object.isRequired,
};
- static contextTypes = {
- intl: intlShape.isRequired,
- };
-
openLink = () => {
const {link} = this.props;
- const {intl} = this.context;
-
- if (link) {
- Linking.openURL(link).catch(() => {
- Alert.alert(
- intl.formatMessage({
- id: 'mobile.link.error.title',
- defaultMessage: 'Error',
- }),
- intl.formatMessage({
- id: 'mobile.link.error.text',
- defaultMessage: 'Unable to open the link.',
- }),
- );
- });
+ if (link && Linking.canOpenURL(link)) {
+ Linking.openURL(link);
}
};
diff --git a/app/components/message_attachments/attachment_title.js b/app/components/message_attachments/attachment_title.js
index 7b2ad49da..ab7be0c33 100644
--- a/app/components/message_attachments/attachment_title.js
+++ b/app/components/message_attachments/attachment_title.js
@@ -2,9 +2,8 @@
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
-import {Alert, Linking, Text, View} from 'react-native';
+import {Linking, Text, View} from 'react-native';
import PropTypes from 'prop-types';
-import {intlShape} from 'react-intl';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import Markdown from 'app/components/markdown';
@@ -16,27 +15,10 @@ export default class AttachmentTitle extends PureComponent {
value: PropTypes.string,
};
- static contextTypes = {
- intl: intlShape.isRequired,
- };
-
openLink = () => {
const {link} = this.props;
- const {intl} = this.context;
-
- if (link) {
- Linking.openURL(link).catch(() => {
- Alert.alert(
- intl.formatMessage({
- id: 'mobile.link.error.title',
- defaultMessage: 'Error',
- }),
- intl.formatMessage({
- id: 'mobile.link.error.text',
- defaultMessage: 'Unable to open the link.',
- }),
- );
- });
+ if (link && Linking.canOpenURL(link)) {
+ Linking.openURL(link);
}
};
diff --git a/app/screens/client_upgrade/client_upgrade.js b/app/screens/client_upgrade/client_upgrade.js
index 3affdd367..166788f52 100644
--- a/app/screens/client_upgrade/client_upgrade.js
+++ b/app/screens/client_upgrade/client_upgrade.js
@@ -105,7 +105,11 @@ export default class ClientUpgrade extends PureComponent {
const {downloadLink} = this.props;
const {intl} = this.context;
- Linking.openURL(downloadLink).catch(() => {
+ Linking.canOpenURL(downloadLink).then((supported) => {
+ if (supported) {
+ return Linking.openURL(downloadLink);
+ }
+
Alert.alert(
intl.formatMessage({
id: 'mobile.client_upgrade.download_error.title',
@@ -116,6 +120,8 @@ export default class ClientUpgrade extends PureComponent {
defaultMessage: 'An error occurred while trying to open the download link.',
}),
);
+
+ return false;
});
};
diff --git a/app/screens/settings/general/settings.js b/app/screens/settings/general/settings.js
index 41ff15f10..70a40d9c5 100644
--- a/app/screens/settings/general/settings.js
+++ b/app/screens/settings/general/settings.js
@@ -5,7 +5,6 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {intlShape, injectIntl} from 'react-intl';
import {
- Alert,
Linking,
Platform,
ScrollView,
@@ -136,42 +135,27 @@ class Settings extends PureComponent {
});
openErrorEmail = preventDoubleTap(() => {
- const {config, intl} = this.props;
+ const {config} = this.props;
const recipient = config.SupportEmail;
const subject = `Problem with ${config.SiteName} React Native app`;
const mailTo = `mailto:${recipient}?subject=${subject}&body=${this.errorEmailBody()}`;
- Linking.openURL(mailTo).then(() => {
- this.props.actions.clearErrors();
- }).catch(() => {
- Alert.alert(
- intl.formatMessage({
- id: 'mobile.mailTo.error.title',
- defaultMessage: 'Error',
- }),
- intl.formatMessage({
- id: 'mobile.mailTo.error.text',
- defaultMessage: 'Unable to open an email client.',
- }),
- );
+ Linking.canOpenURL(mailTo).then((supported) => {
+ if (supported) {
+ Linking.openURL(mailTo);
+ this.props.actions.clearErrors();
+ }
});
});
openHelp = preventDoubleTap(() => {
- const {config, intl} = this.props;
+ const {config} = this.props;
const link = config.HelpLink ? config.HelpLink.toLowerCase() : '';
- Linking.openURL(link).catch(() => {
- Alert.alert(
- intl.formatMessage({
- id: 'mobile.link.error.title',
- defaultMessage: 'Error',
- }),
- intl.formatMessage({
- id: 'mobile.link.error.text',
- defaultMessage: 'Unable to open the link.',
- }),
- );
+ Linking.canOpenURL(link).then((supported) => {
+ if (supported) {
+ Linking.openURL(link);
+ }
});
});
diff --git a/app/utils/supported_server.ts b/app/utils/supported_server.ts
index 97e29e533..36bea7c84 100644
--- a/app/utils/supported_server.ts
+++ b/app/utils/supported_server.ts
@@ -36,18 +36,9 @@ function unsupportedServerAdminAlert(formatMessage: FormatMessageType) {
style: 'cancel',
onPress: () => {
const url = 'https://mattermost.com/blog/support-for-esr-5-9-has-ended/';
- Linking.openURL(url).catch(() => {
- Alert.alert(
- formatMessage({
- id: 'mobile.link.error.title',
- defaultMessage: 'Error',
- }),
- formatMessage({
- id: 'mobile.link.error.text',
- defaultMessage: 'Unable to open the link.',
- }),
- );
- });
+ if (Linking.canOpenURL(url)) {
+ Linking.openURL(url);
+ }
},
};
const buttons: AlertButton[] = [cancel, learnMore];
diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json
index 80e8a873f..3a4fe5035 100644
--- a/assets/base/i18n/en.json
+++ b/assets/base/i18n/en.json
@@ -290,16 +290,12 @@
"mobile.ios.photos_permission_denied_description": "Upload photos and videos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your photo and video library.",
"mobile.ios.photos_permission_denied_title": "{applicationName} would like to access your photos",
"mobile.join_channel.error": "We couldn't join the channel {displayName}. Please check your connection and try again.",
- "mobile.link.error.text": "Unable to open the link.",
- "mobile.link.error.title": "Error",
"mobile.loading_channels": "Loading Channels...",
"mobile.loading_members": "Loading Members...",
"mobile.loading_options": "Loading Options...",
"mobile.loading_posts": "Loading messages...",
"mobile.login_options.choose_title": "Choose your login method",
"mobile.long_post_title": "{channelName} - Post",
- "mobile.mailTo.error.text": "Unable to open an email client.",
- "mobile.mailTo.error.title": "Error",
"mobile.managed.blocked_by": "Blocked by {vendor}",
"mobile.managed.exit": "Exit",
"mobile.managed.jailbreak": "Jailbroken devices are not trusted by {vendor}, please exit the app.",
diff --git a/ios/Mattermost/Info.plist b/ios/Mattermost/Info.plist
index 70e6e8efb..541e130cd 100644
--- a/ios/Mattermost/Info.plist
+++ b/ios/Mattermost/Info.plist
@@ -129,5 +129,10 @@
UIViewControllerBasedStatusBarAppearance
+ LSApplicationQueriesSchemes
+
+ https
+ http
+
diff --git a/test/setup.js b/test/setup.js
index 6a43001c5..2c53ff475 100644
--- a/test/setup.js
+++ b/test/setup.js
@@ -187,6 +187,7 @@ jest.mock('react-native-cookies', () => ({
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
openURL: jest.fn(),
+ canOpenURL: jest.fn(),
getInitialURL: jest.fn(),
clearAll: jest.fn(),
get: () => Promise.resolve(({