I have a UIViewController
with a UITextView
that auto-detects hyperlinks in its text. It works properly, but I'd to use SFSafariViewController
to open the links so I stay "inside" my app, rather than opening a separate browser, which is the "out of the box" behavior.
I've taken the steps outline below, but websites still open a separate Safari browser, rather than inside my app. I get no errors or warnings, but the websites detected still open in a separate browser, not within my app. The UITextViewDelegate
method doesn't appear to be getting called (I threw a log statement in to check).
I looked at UITextViewDelegate
and I think I want to use this method to open the website that's detected by the UITextView
:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange {
// Fill code in here to use SFSafariViewController
return YES;
}
What I've done so far:
1) Imported SafariServices, made delegate declaration, and declared a delegate property in MyViewController.h
@import SafariServices;
@interface MyViewController : UIViewController <UITextViewDelegate, SFSafariViewControllerDelegate>
@property(nonatomic, weak, nullable) id< SFSafariViewControllerDelegate, SFSafariViewControllerDelegate > delegate;
2) Added a delegate section to my .m file and tried to fill in this method from the stub above:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange {
SFSafariViewController *websiteToOpen = [[SFSafariViewController alloc]initWithURL:URL entersReaderIfAvailable:YES];
websiteToOpen.delegate = self;
[self presentViewController:websiteToOpen animated:YES completion:nil];
return YES;
}
I'm certain it's 100% me mucking this up, but I'm unable to get over the finish line. What am I missing?
in case someone is looking for Swift 3 implementation.
Solution that works:
1.Importing Safari Services
import SafariServices
2.Creating attributed text, adding link to it, assigning string to textView
let myLink = "google.com"
let myText = "here is my link: \(myLink)"
let myAttributedText = NSMutableAttributedString(string: myText)
let rangeOfMyLink = myText.range(of: myLink)
if rangeOfMyLink.location != NSNotFound {
myAttributedText.addAttributes([NSLinkAttributeName: myLink], range: rangeOfMyLink)
}
myTextView.attributedText = myAttributedText
myTextView.delegate = self
3.Add Delegate to VC:
class MyViewController: UIViewController, UITextViewDelegate
4.Adding Delegate method:
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
let safariVC = SFSafariViewController(url: URL)
present(safariVC, animated: true, completion: nil)
return false
}
Hope it helps!
I am trying to do the same thing, but having different problems.
Firstly, you'll need to set your text view's delegate for the delegate
method to fire. I do this in viewDidLoad:
myTextView.delegate = self;
Then, tell your UITextView
not to interact with the URL:
- (BOOL)textView:(UITextView *)textView
shouldInteractWithURL:(NSURL *)url
inRange:(NSRange)characterRange
{
[self presentViewController:websiteToOpen animated:YES completion:nil];
return NO;
}
With this, I can present the safari view controller, although it is empty, i.e. no content and no Done button. So I'm doing something else wrong...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With