Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open website with SFSafariViewController from UITextView auto detected link

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?

like image 359
Adrian Avatar asked Oct 08 '15 03:10

Adrian


2 Answers

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!

like image 60
Tung Fam Avatar answered Oct 13 '22 00:10

Tung Fam


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...

like image 27
time_trial Avatar answered Oct 12 '22 23:10

time_trial