Search code examples
iosswiftuitextviewnsattributedstring

UITextView href link not working


This is the text to be displayed :

© Gregory A. Dunbar <a href=\"http://gregoryadunbar.com\" rel=\"nofollow\">gregoryadunbar.com</a>\n  

This is the code I am using to display UITextView and trigger link :

Here p.caption is the above string

textViewCaption = UITextView(frame: CGRect(x: labelPadding, y: 0.0, width: self.bounds.size.width - labelPadding * 2.0, height: self.bounds.size.height))
        textViewCaption.delegate = self
        textViewCaption.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        textViewCaption.isOpaque = false
        textViewCaption.backgroundColor = UIColor.black
        textViewCaption.textAlignment = NSTextAlignment.center

        textViewCaption.textColor = UIColor.white
        textViewCaption.font = UIFont.systemFont(ofSize: 17.0)
        textViewCaption.isEditable = false
        textViewCaption.isSelectable = true
        textViewCaption.dataDetectorTypes = .link

        if let p = media  {
            let htmlData = NSString(string:String(format: "<HTML><body><font size='4'>%@</font></body></HTML>", p.caption)).data(using: String.Encoding.unicode.rawValue)

            let attributedString = try! NSAttributedString(data: htmlData!, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
            textViewCaption.attributedText = attributedString
        }

        self.addSubview(textViewCaption)  

This is the delegate call to check the link :

public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {

            if #available(iOS 10.0, *) {
                UIApplication.shared.open(URL, options: [:])
            } else {
                UIApplication.shared.openURL(URL)
            }

        return true
    }  

Note : All this is in a custom view.

This is the response :

enter image description here

So I have two issues here :

  1. Text not shown completely.
  2. Link not clickable.

Solution

  • Links with http instead of https are blocked by default. You need to add an exception in your info.plist

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>gregoryadunbar.com</key>
            <dict>
                <key>NSIncludesSubdomains</key>
                <true/>
            </dict>
        </dict>
    </dict>
    

    or allow all unsecure links

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    

    Also, there's much easier way to add clickable links to attributed string, instead of constructing a HTML document you can do

    let text = "your full string including link gregoryadunbar.com"
    let range = text.range(of: "gregoryadunbar.com")
    
    let attributedText = NSMutableAttributedString(string: text)
    attributedText.addAttribute(.link, value: "http://gregoryadunbar.com", range: range)
    attributedText.addAttribute(.font, value: someFont, range: Range(location: 0, length: text.characters.count))
    attributedText.addAttribute(.foregroundColor, value: UIColor.white range: Range(location: 0, length: text.characters.count))
    

    if you don't set UITextView's delegate, this should work by default

    If your links are wrapped in a href tag, you can strip all the HTML tags in your link like so:

    let link = "A. Dunbar <a href=\"http://gregoryadunbar.com\" rel=\"nofollow\">gregoryadunbar.com</a>\n"
    let linkWithoutHtmlTags = link.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil) // gregoryadunbar.com