I'm trying to open url from messages embedded in an NSAttributedString. I'm using the latest version of MessageKit and Swift 5. I'm using the function didSelectURL, but it doesn't seem to reach that part of the code. I came across this solution on Stack Overflow, but I wanted to follow up with regards to how to set up MessageLabelDelegate. Just like in the linked solution, I have implemented the delegate methods detectorAttributes and enabledDetectors.
I currently have MessageLabelDelegate set up as an extension to my ViewController, but it never seems to reach those methods.
extension ChatViewController:MessageLabelDelegate {
func didSelectURL(_url: URL) {
// .. open URL
}
}
It seems to be getting overwritten by the method didTapMessage in the MessageCellDelegate extension. I tried going through the example code in the MessageKit repo, but still unclear as to how it's meant to be set up or what I'm doing wrong. Any help will be greatly appreciated!
Hey @gastonar Thanks for opening an issue! 馃槉
You need to set messagesCollectionView.messageCellDelegate = self somewhere in your view controller (most likely in your viewDidLoad).
You can see an example of how this is done in ChatViewController.swift in the example project. If not already, your view controller needs to conform to MessageCellDelegate which is actually a subclass of MessageLabelDelegate. You can see this working if you run the example project, enable URL messages in the settings, then in the Advanced Example you can then click URL messages and you'll see URL Selected: https://github.com/MessageKit printed to the console.
In the end the code would be something like:
class ChatViewController: MessagesViewController {
override func viewDidLoad() {
super.viewDidLoad()
messagesCollectionView.messagesDisplayDelegate = self
messagesCollectionView.messageCellDelegate = self
// etc ...
}
// etc ...
}
extension ChatViewController: MessagesDisplayDelegate {
func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] {
return [.url]
}
// etc ...
}
extension ChatViewController: MessageCellDelegate {
func didSelectURL(_url: URL) {
// .. open URL
}
}
In the example project it splits up the MessageCellDelegate extension and the MessageLabelDelegate extension for organization purposes but in the end since MessageCellDelegate is a subclass of MessageLabelDelegate you only have to set the delegate on the collection view in one place, and if you don't want to split them up or are not using any MessageCellDelegate methods you can also just write one extension like the above example.
I can see how this is confusing so this is somewhere where we could maybe improve our documentation, so thanks for bringing it to our attention! (PRs are also welcome if that's something you'd like to contribute). LMK if this helps you.
Hi @kinoroy, thank you so much for your quick and detailed response. I tried your suggestion but it still doesn't seem to be working for me.
I currently declare ChatViewController as:
class ChatViewController: MessagesViewController, MessagesDataSource, MessagesLayoutDelegate, MessagesDisplayDelegate
In my viewDidLoad, I include all the necessary calls:
messagesCollectionView.messagesDataSource = self
messagesCollectionView.messagesLayoutDelegate = self
messagesCollectionView.messagesDisplayDelegate = self
messageInputBar.delegate = self
messagesCollectionView.messageCellDelegate = self
In ChatViewController itself, I include the enabledDetectors and detectorAttributes (since I basically included the MessagesDisplayDelegate extension when I declared the class).
Then I have the MessageCellDelegate extension. I do use some of the functions in MessageCellDelegate such as didTapMessage, didTapImage and didTapPlayButton. All those functions work perfectly for me. I tried commenting out didTapMessage, but that didn't solve my issue. I tried adding didSelectURL directly in this extension, but that didn't work out.
I then tried to create a separate extension for MessageLabelDelegate containing the didSelectURL method, but that didn't work either.
Just to clarify, I'm having the issue when I try using a hyperlinked text instead of displaying the entire URL. For example, writing File Received instead of https://www.google.com. When I display the entire link, didSelectURL does work, but when I have hyperlinked text, it does not recognize it as a URL.
Just to clarify, I'm having the issue when I try using a hyperlinked text instead of displaying the entire URL.
Ahh, sorry I didn't catch that earlier.
How are you adding the link to your string? Are you setting the value of the link attribute to be a URL object or a string? MessageKit expects a URL object. Something like this should work:
lazy var text: NSMutableAttributedString = {
let text = NSMutableAttributedString(string: "Check out this cool link")
text.addAttribute(.link, value: URL(string: "https://github.com/MessageKit/MessageKit"), range: NSRange(location: 0, length: text.string.count))
return text
}()
I created a bare-minimum repo showing this working with the embedded link attributed string, you can check it out (if you've never used cocoapods, make sure you open the .xcworkspace not the .xcodeproj, other than that you should be able to open and run it): https://github.com/kinoroy/MessageKitUrlDetectorExample
Yesss! That was my error... I had set
text.addAttribute(.link, value : <string-representation-of-URL>)
instead of
text.addAttribute(.link, value : URL(string : <string-representation-of-URL>))
Thank you so much! I was stuck on this for a couple days, so really appreciate the help!