15

I'm developing and iPhone 3.0 application. And I'm trying to open web links in a UITextView into a UIWebView instead of Safari. But still no luck.

The UITextView is not editable, and it perfectly detects web links and open them in Safari.

How to avoid that? How to grab that url so i can use with my own UIWebView?

Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
lucadb
  • 422
  • 1
  • 6
  • 15

3 Answers3

22

This is an old question but incase anyone is looking for an updated way of doing this.

Assign your viewController that holds the UITextView as a delegate in your viewController's .m file and just add:

-(BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange{

    //Do something with the URL
    NSLog(@"%@", URL);


    return NO;
}
nihad
  • 221
  • 2
  • 2
8

With Swift 3, UITextViewDelegate provides a textView(_:shouldInteractWith:in:interaction:) method. textView(_:shouldInteractWith:in:interaction:) has the following declaration:

Asks the delegate if the specified text view should allow the specified type of user interaction with the given URL in the given range of text.

optional func textView(_ textView: UITextView,  shouldInteractWith URL: URL,  in characterRange: NSRange,  interaction: UITextItemInteraction) -> Bool

The following code shows how to open UITextView web links in a SFSafariViewController instead of opening them in Safari app:

import UIKit
import SafariServices

class ViewController: UIViewController, UITextViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set textView
        let textView = UITextView()
        textView.text = "http://www.yahoo.fr http://www.google.fr"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = UIDataDetectorTypes.link

        // Add view controller as the textView's delegate
        textView.delegate = self

        // auto layout
        view.addSubview(textView)
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.heightAnchor.constraint(equalToConstant: 300).isActive = true
        textView.widthAnchor.constraint(equalToConstant: 300).isActive = true
    }

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        // Open links with a SFSafariViewController instance and return false to prevent the system to open Safari app
        let safariViewController = SFSafariViewController(url: URL)
        present(safariViewController, animated: true, completion: nil)

        return false
    }

}
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
7

The simplest way is to override the webView:decidePolicyForNavigationAction:request:frame:decisionListener: method on UITextView like so:

@interface UITextView (Override)
@end

@class WebView, WebFrame;
@protocol WebPolicyDecisionListener;

@implementation UITextView (Override)

- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id < WebPolicyDecisionListener >)listener
{
    NSLog(@"request: %@", request);
}
@end

This will affect all UITextViews in your application. If you only require this on a single view, create a subclass and override the method on that.

Note: this is technically a private API and could be removed at any time. There is no way to do this via the public API.

edit: as of iOS 7.0 a new method has been introduced on UITextViewDelegate to support this. See nihad's answer for details.

rpetrich
  • 32,196
  • 6
  • 66
  • 89
  • 1
    Uhm, being private, do you think it's gonna be a problem for appstore approval? Btw tonight i'll check your code and i'll let you know. Thanks. – lucadb Aug 20 '09 at 17:49
  • This isn't the sort of thing they can check for, but you may be at a slight risk for future OS changes (this is a public API in the desktop equivalent and it's unlikely that Apple will stop using WebKit, but it's possible). The worst that can happen is the behaviour will return to the default of launching MobileSafari. – rpetrich Aug 20 '09 at 17:59
  • Nice! Another answer is to override [UIApplication openURL:(NSURL *) url ] http://stackoverflow.com/questions/1889262/iphone-sdk-opening-links-in-a-uitextview-in-a-web-view/2251898#2251898 – tt.Kilew Feb 12 '10 at 13:04
  • @crash - did you ever submit an app using this code? Was it rejected or did it pass? Does anyone else here have any apps that were approved using this code? – Jasarien Mar 21 '10 at 22:27
  • 1
    I wouldn't risk it. I'm not sure if subclassing UIApplication and overriding openURL: is considered private; it probably is, but is closer to public APIs than my answer – rpetrich Mar 22 '10 at 07:22
  • Apple now machine scan code for illegal APIs. I'm certain this is not going to get past them now. – Rog Mar 24 '10 at 17:17
  • I've never submitted an app using this code. I totally agree with @rpetrich and @Roger Nolan – lucadb Mar 27 '10 at 01:32
  • @rpetrich Can someone clarify where I would put the code above? I have been developing some apps for about 6 months, but I'm still fuzzy about file structure and anything related to extending base classes. Where would I put this code and what sort of file name would it need? I know how to do it if subclassing UITextView, but if not doing so where does this go? – sunny Jun 23 '15 at 14:56