Skip to content

In App Safari View Controller Support. #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Custom Tabs is supported only for Android, so the behavior on each platform is b
If Chrome is installed, open the URL in Chrome that you have customized some of the look & feel. If it is not installed, open in other browser.

* iOS
If Chrome is installed, open the URL in it. If it is not installed, open in Safari.
Presents SafariViewController by default for iOS >9.0. Else opens in Safari.

Customization and detailed behavior refer to the [Usage](#Usage).

Expand Down
11 changes: 11 additions & 0 deletions ios/ReactNativeCustomTabs.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
BBADAF32239FC95A00E94359 /* SafariViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BBADAF31239FC95A00E94359 /* SafariViewManager.m */; };
DA7118851CC916080087DF95 /* DBChromeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA7118551CC90B700087DF95 /* DBChromeManager.m */; };
/* End PBXBuildFile section */

Expand All @@ -23,6 +24,8 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
BBADAF30239FC95A00E94359 /* SafariViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SafariViewManager.h; path = ReactNativeCustomTabs/SafariViewManager.h; sourceTree = "<group>"; };
BBADAF31239FC95A00E94359 /* SafariViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SafariViewManager.m; path = ReactNativeCustomTabs/SafariViewManager.m; sourceTree = "<group>"; };
DA7118541CC90B700087DF95 /* DBChromeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DBChromeManager.h; path = ReactNativeCustomTabs/DBChromeManager.h; sourceTree = "<group>"; };
DA7118551CC90B700087DF95 /* DBChromeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DBChromeManager.m; path = ReactNativeCustomTabs/DBChromeManager.m; sourceTree = "<group>"; };
DA7118681CC9158A0087DF95 /* libDBCustomTabs.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDBCustomTabs.a; sourceTree = BUILT_PRODUCTS_DIR; };
Expand All @@ -42,6 +45,8 @@
13B07FAE1A68108700A75B9A /* ReactNativeCustomTabs */ = {
isa = PBXGroup;
children = (
BBADAF30239FC95A00E94359 /* SafariViewManager.h */,
BBADAF31239FC95A00E94359 /* SafariViewManager.m */,
DA7118541CC90B700087DF95 /* DBChromeManager.h */,
DA7118551CC90B700087DF95 /* DBChromeManager.m */,
);
Expand Down Expand Up @@ -106,6 +111,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
Expand All @@ -123,6 +129,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BBADAF32239FC95A00E94359 /* SafariViewManager.m in Sources */,
DA7118851CC916080087DF95 /* DBChromeManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -226,6 +233,8 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../react-native/React/**/**",
"$(SRCROOT)/../../react-native/React/**",
"${SRCROOT}/../../../ios/Pods/Headers/Public/**",
);
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -242,6 +251,8 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../react-native/React/**/**",
"$(SRCROOT)/../../react-native/React/**",
"${SRCROOT}/../../../ios/Pods/Headers/Public/**",
);
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down
20 changes: 20 additions & 0 deletions ios/ReactNativeCustomTabs/SafariViewManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// SafariViewManager.h
// DBCustomTabs
//
// Created by Avinash on 10/12/2019.
// Copyright © 2019 Facebook. All rights reserved.
//

#import "RCTEventEmitter.h"
#import <React/RCTBridgeModule.h>

@import SafariServices;

NS_ASSUME_NONNULL_BEGIN

@interface SafariViewManager : RCTEventEmitter<RCTBridgeModule, SFSafariViewControllerDelegate>

@end

NS_ASSUME_NONNULL_END
119 changes: 119 additions & 0 deletions ios/ReactNativeCustomTabs/SafariViewManager.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//
// SafariViewManager.m
// DBCustomTabs
//
// Created by Avinash on 10/12/2019.
// Copyright © 2019 Facebook. All rights reserved.
//

#import "SafariViewManager.h"
#import <React/RCTUtils.h>
#import <React/RCTLog.h>
#import <React/RCTConvert.h>

@implementation SafariViewManager
{
bool hasListeners;
SFSafariViewController *_safariView;
}

RCT_EXPORT_MODULE()

- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}

- (void)startObserving
{
hasListeners = YES;
}

- (void)stopObserving
{
hasListeners = NO;
}

- (NSArray<NSString *> *)supportedEvents
{
return @[@"SafariViewOnShow", @"SafariViewOnDismiss"];
}

RCT_EXPORT_METHOD(show:(NSDictionary *)args resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
// Error if no url is passed
if (!args[@"url"]) {
reject(@"E_SAFARI_VIEW_NO_URL", @"You must specify a url.", nil);
return;
}

NSURL *url = [RCTConvert NSURL:args[@"url"]];
BOOL readerMode = [args[@"readerMode"] boolValue];
UIColor *tintColorString = args[@"tintColor"];
UIColor *barTintColorString = args[@"barTintColor"];
BOOL fromBottom = [args[@"fromBottom"] boolValue];

// Initialize the Safari View
_safariView = [[SFSafariViewController alloc] initWithURL:url entersReaderIfAvailable:readerMode];
_safariView.delegate = self;

// Set tintColor if available
if (tintColorString) {
UIColor *tintColor = [RCTConvert UIColor:tintColorString];
if ([_safariView respondsToSelector:@selector(setPreferredControlTintColor:)]) {
[_safariView setPreferredControlTintColor:tintColor];
} else {
[_safariView.view setTintColor:tintColor];
}
}

// Set barTintColor if available
if (barTintColorString) {
UIColor *barTintColor = [RCTConvert UIColor:barTintColorString];
if ([_safariView respondsToSelector:@selector(setPreferredBarTintColor:)]) {
[_safariView setPreferredBarTintColor:barTintColor];
}
}

// Set modal transition style
if (fromBottom) {
_safariView.modalPresentationStyle = UIModalPresentationOverFullScreen;
}

// get the view controller closest to the foreground
UIViewController *ctrl = RCTPresentedViewController();

// Display the Safari View
[ctrl presentViewController:_safariView animated:YES completion:nil];

if (hasListeners) {
[self sendEventWithName:@"SafariViewOnShow" body:nil];
}

resolve(@YES);
}

RCT_EXPORT_METHOD(isAvailable:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
if (@available(iOS 9.0, *)) {
// SafariView is available
resolve(@YES);
} else {
reject(@"E_SAFARI_VIEW_UNAVAILABLE", @"SafariView is unavailable", nil);
}
}

RCT_EXPORT_METHOD(dismiss)
{
[_safariView dismissViewControllerAnimated:true completion:nil];
}

-(void)safariViewControllerDidFinish:(nonnull SFSafariViewController *)controller
{
_safariView = nil;
NSLog(@"[SafariView] SafariView dismissed.");
if (hasListeners) {
[self sendEventWithName:@"SafariViewOnDismiss" body:nil];
}
}
@end
Loading