Chrome Custom Tabs for Android & SafariServices/AuthenticationServices for iOS.
$ npm install react-native-inappbrowser-reborn --save
Linking the package manually is not required anymore with Autolinking.
-
iOS Platform:
$ cd ios && pod install && cd ..
# CocoaPods on iOS needs this extra step -
Android Platform with Android Support:
Using Jetifier tool for backward-compatibility.
Modify your android/build.gradle configuration:
buildscript { ext { buildToolsVersion = "28.0.3" minSdkVersion = 16 compileSdkVersion = 28 targetSdkVersion = 28 # Only using Android Support libraries supportLibVersion = "28.0.0" }
-
Android Platform with AndroidX:
Modify your android/build.gradle configuration:
buildscript { ext { buildToolsVersion = "28.0.3" minSdkVersion = 16 compileSdkVersion = 28 targetSdkVersion = 28 # Remove 'supportLibVersion' property and put specific versions for AndroidX libraries androidXAnnotation = "1.1.0" androidXBrowser = "1.0.0" // Put here other AndroidX dependencies }
$ react-native link react-native-inappbrowser-reborn
- In XCode, in the project navigator, right click
Libraries
➜Add Files to [your project's name]
- Go to
node_modules
➜react-native-inappbrowser-reborn
and addRNInAppBrowser.xcodeproj
- In XCode, in the project navigator, select your project. Add
libRNInAppBrowser.a
to your project'sBuild Phases
➜Link Binary With Libraries
- Run your project (
Cmd+R
)<
- Open up
ios/Podfile
- Add
pod 'RNInAppBrowser', :path => '../node_modules/react-native-inappbrowser-reborn'
- Run
pod install
- Open up
android/app/src/main/java/[...]/MainApplication.java
- Add
import com.proyecto26.inappbrowser.RNInAppBrowserPackage;
to the imports at the top of the file - Add
new RNInAppBrowserPackage()
to the list returned by thegetPackages()
method
- Append the following lines to
android/settings.gradle
:include ':react-native-inappbrowser-reborn' project(':react-native-inappbrowser-reborn').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-inappbrowser-reborn/android')
- Insert the following lines inside the dependencies block in
android/app/build.gradle
:implementation project(':react-native-inappbrowser-reborn')
- Update ProGuard config (Optional)
- Append the following lines to your ProGuard config (
proguard-rules.pro
)-keepattributes *Annotation* -keepclassmembers class ** { @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; }
Methods | Action |
---|---|
open |
Opens the url with Safari in a modal on iOS using SFSafariViewController, and Chrome in a new custom tab on Android. On iOS, the modal Safari will not share cookies with the system Safari. |
close |
Dismisses the system's presented web browser. |
openAuth |
Opens the url with Safari in a modal on iOS using SFAuthenticationSession/ASWebAuthenticationSession, and Chrome in a new custom tab on Android. On iOS, the user will be asked whether to allow the app to authenticate using the given url (OAuth flow with deep linking redirection). |
closeAuth |
Dismisses the current authentication session. |
isAvailable |
Detect if the device supports this plugin. |
Property | Description |
---|---|
dismissButtonStyle (String) |
The style of the dismiss button. [done /close /cancel ] |
preferredBarTintColor (String) |
The color to tint the background of the navigation bar and the toolbar. [white /#FFFFFF ] |
preferredControlTintColor (String) |
The color to tint the control buttons on the navigation bar and the toolbar. [gray /#808080 ] |
readerMode (Boolean) |
A value that specifies whether Safari should enter Reader mode, if it is available. [true /false ] |
animated (Boolean) |
Animate the presentation. [true /false ] |
modalPresentationStyle (String) |
The presentation style for modally presented view controllers. [automatic /none /fullScreen /pageSheet /formSheet /currentContext /custom /overFullScreen /overCurrentContext /popover ] |
modalTransitionStyle (String) |
The transition style to use when presenting the view controller. [coverVertical /flipHorizontal /crossDissolve /partialCurl ] |
modalEnabled (Boolean) |
Present the SafariViewController modally or as push instead. [true /false ] |
enableBarCollapsing (Boolean) |
Determines whether the browser's tool bars will collapse or not. [true /false ] |
ephemeralWebSession (Boolean) |
Prevent re-use cookies of previous session (openAuth only) [true /false ] |
Property | Description |
---|---|
showTitle (Boolean) |
Sets whether the title should be shown in the custom tab. [true /false ] |
toolbarColor (String) |
Sets the toolbar color. [gray /#808080 ] |
secondaryToolbarColor (String) |
Sets the color of the secondary toolbar. [white /#FFFFFF ] |
enableUrlBarHiding (Boolean) |
Enables the url bar to hide as the user scrolls down on the page. [true /false ] |
enableDefaultShare (Boolean) |
Adds a default share item to the menu. [true /false ] |
animations (Object) |
Sets the start and exit animations. [{ startEnter, startExit, endEnter, endExit } ] |
headers (Object) |
The data are key/value pairs, they will be sent in the HTTP request headers for the provided url. [{ 'Authorization': 'Bearer ...' } ] |
forceCloseOnRedirection (Boolean) |
Open Custom Tab in a new task to avoid issues redirecting back to app scheme. [true /false ] |
import { Linking } from 'react-native'
import InAppBrowser from 'react-native-inappbrowser-reborn'
...
async openLink() {
try {
const url = 'https://www.google.com'
if (await InAppBrowser.isAvailable()) {
const result = await InAppBrowser.open(url, {
// iOS Properties
dismissButtonStyle: 'cancel',
preferredBarTintColor: '#453AA4',
preferredControlTintColor: 'white',
readerMode: false,
animated: true,
modalPresentationStyle: 'overFullScreen',
modalTransitionStyle: 'partialCurl',
modalEnabled: true,
enableBarCollapsing: false,
// Android Properties
showTitle: true,
toolbarColor: '#6200EE',
secondaryToolbarColor: 'black',
enableUrlBarHiding: true,
enableDefaultShare: true,
forceCloseOnRedirection: false,
// Specify full animation resource identifier(package:anim/name)
// or only resource name(in case of animation bundled with app).
animations: {
startEnter: 'slide_in_right',
startExit: 'slide_out_left',
endEnter: 'slide_in_left',
endExit: 'slide_out_right'
},
headers: {
'my-custom-header': 'my custom header value'
}
})
Alert.alert(JSON.stringify(result))
}
else Linking.openURL(url)
} catch (error) {
Alert.alert(error.message)
}
}
...
In order to redirect back to your application from a web browser, you must specify a unique URI to your app. To do this,
define your app scheme and replace my-scheme
and my-host
with your info.
- Enable deep linking (Android) - AndroidManifest.xml
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="my-scheme" android:host="my-host" android:pathPrefix="" />
</intent-filter>
- Enable deep linking (iOS) - Info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>my-scheme</string>
<key>CFBundleURLSchemes</key>
<array>
<string>my-scheme</string>
</array>
</dict>
</array>
- utilities.js
import { Platform } from 'react-native'
export const getDeepLink = (path = "") => {
const scheme = 'my-scheme'
const prefix = Platform.OS == 'android' ? `${scheme}://my-host/` : `${scheme}://`
return prefix + path
}
import { Root } from 'native-base'
import { getDeepLink } from './utilities'
import { createStackNavigator } from 'react-navigation'
const Main = createStackNavigator(
{
SplashComponent: { screen: SplashComponent },
LoginComponent: { screen: LoginComponent },
HomeComponent: { screen: HomeComponent },
CallbackComponent: { //Redirect users to the Home page if they are authenticated, otherwise to Login page...
screen: CallbackComponent,
path: 'callback/' //Enable Deep linking redirection to get the auth_token
}
},
{
index: 0,
initialRouteName: 'SplashComponent',
headerMode: 'none'
}
)
...
render() {
return (
<Root>
<Main uriPrefix={getDeepLink()} />
</Root>
)
}
...
- LoginComponent
import { Linking } from 'react-native'
import InAppBrowser from 'react-native-inappbrowser-reborn'
import { getDeepLink } from './utilities'
...
async onLogin() {
const deepLink = getDeepLink("callback")
const url = `https://my-auth-login-page.com?redirect_uri=${deepLink}`
try {
if (await InAppBrowser.isAvailable()) {
InAppBrowser.openAuth(url, deepLink, {
// iOS Properties
dismissButtonStyle: 'cancel',
ephemeralWebSession: false,
// Android Properties
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: true
}).then((response) => {
if (response.type === 'success' &&
response.url) {
Linking.openURL(response.url)
}
})
} else Linking.openURL(url)
} catch (error) {
Linking.openURL(url)
}
}
...
- SplashComponent
...
async componentDidMount() {
// Play Lottie Animation :)
// Validate the stored access token (Maybe with a request)
// Redirect the user to the Home page if the token is still valid
// Otherwise redirect to the Login page
}
...
- CallbackComponent
...
async componentDidMount() {
// Play Lottie Animation :)
try {
await this.loadUserInfo()
// Redirect to the Home page
} catch (error) {
// Show error and redirect the user to the Login page
}
}
async loadUserInfo() {
const { navigation } = this.props
const { state: { params } } = navigation
const { code, error } = params || {}
if (code) {
// Get and Save the access token request, user info...
}
else {
return Promise.reject(new Error(error))
}
}
...
The StatusBar will keep the last one provided in your app. So if the StatusBar is dark-content
before you open the browser this will keep it.
Starting with React Native 0.59 onwards, there is a simpler way of handling this update, without the need of patching StatusBar.
async openInBrowser(url) {
try {
const oldStyle = StatusBar.pushStackEntry({ barStyle: 'dark-content', animate: false });
await InAppBrowser.open(url)
StatusBar.popStackEntry(oldStyle);
} catch (error) {
Alert.alert(error.message)
}
})
For previous versions, you can still apply the method described below.
If you want to change before opening you can do something like
async openInBrowser(url) {
try {
StatusBar.setBarStyle('dark-content')
await InAppBrowser.open(url)
} catch (error) {
Alert.alert(error.message)
}
})
If you need to restore the old bar style, after the browser is dismissed, you can try and patch the StatusBar.setBarStyle function to store the old value like so:
// patch StatusBar.setBarStyle to make style accessible
const _setBarStyle = StatusBar.setBarStyle
StatusBar.setBarStyle = (style) => {
StatusBar.currentStyle = style
_setBarStyle(style)
}
You can than restore the old bar style after the browser has been dismissed like this:
async openInBrowser(url) {
try {
const oldStyle = StatusBar.currentStyle
StatusBar.setBarStyle('dark-content')
await InAppBrowser.open(url)
if(oldStyle) StatusBar.setBarStyle(oldStyle)
} catch (error) {
Alert.alert(error.message)
}
})
Using in-app browser tabs (like SFAuthenticationSession/ASWebAuthenticationSession and Android Custom Tabs) where available. Embedded user-agents, known as web-views (like UIWebView and WKWebView), are explicitly not supported due to the usability and security reasons documented in Section 8.12 of RFC 8252.
- Expo: WebBrowser
- React Native Custom Tabs: Chrome Custom Tabs for React Native
- React Native Safari View: A React Native wrapper for Safari View Controller
Please do contribute! Issues and pull requests are welcome.
This project exists thanks to all the people who contribute. [Contribute].
Become a financial contributor and help us sustain our community. [Contribute]
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
I believe in Unicorns 🦄 Support me, if you do too. Professionally supported react-native-inappbrowser-reborn is coming soon
To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure.
Made with ❤️