I'm using Smooch library for integration chat into the app. In addition, I've implemented Universal Links.
Programming language - Swift / iOS version - 12.4+ / Smooch SDK version 7.12
Problem:
- When I am tapping on the link from Smooch chat it opens me Safari browser instead webView!!! Universal link works correctly, I can be redirected by tapping on the link from other Apps (WhatsApp, Safari, telegram ...)
But just taping in the link from the smooch chat redirects me to the Safari browser. How I can stay in the App?
Here main VC where I'm loading webView and button with Smooch chat:
override func viewDidLoad() {
super.viewDidLoad()
if let data = userDefaults.dictionary(forKey: "data"){
responseData = data
}
loadWebKit()
checkToken()
initSmooch()
setupChatBtnView()
}
//showing smooch chat view
@IBAction func chatBtnDidPress(_ sender: UIButton) {
Smooch.show()
}
//chat button design
func setupChatBtnView(){
chatBtnOutlet.layer.cornerRadius = chatBtnOutlet.bounds.self.width / 2.0
chatBtnOutlet.clipsToBounds = true
chatBtnOutlet.layer.shadowRadius = 1
chatBtnOutlet.layer.shadowColor = UIColor(red: 255/255, green: 170/255, blue: 0/255, alpha: 0.5).cgColor
chatBtnOutlet.layer.shadowOpacity = 0.5
chatBtnOutlet.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
chatBtnOutlet.layer.masksToBounds = false
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
Smooch.close()
}
//webkit view url load and adding js event listeners
func loadWebKit(){
webView.navigationDelegate = self
webView.configuration.userContentController.add(self, name: "finishLoading")
webView.configuration.userContentController.add(self, name: "logout")
webView.isHidden = true
activityIndicator.isHidden = false
if appDelegate.externalUrl == nil {
webView.load(URLRequest(url: URL(string: "https://example.com")!))
} else {
deepLinkURL = self.appDelegate.externalUrl!
let urlRequest = URLRequest(url: deepLinkURL!)
self.webView.load(urlRequest)
isFromDeepLing = true
webView.isHidden = true
activityIndicator.isHidden = false
print(urlRequest)
}
}
//when loading url finish call a js functions
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
guard let dataForJS = userDefaults.string(forKey: "dataJs") else {
self.webView.isHidden = false
self.activityIndicator.isHidden = true
return
}
if !isFromDeepLing {
webView.evaluateJavaScript("handleNativeLogin('\(dataForJS)')") { (result, error) in
self.webView.isHidden = false
self.activityIndicator.isHidden = true
}
} else {
if !isUsedDeepLink {
webView.evaluateJavaScript("handleNativeLogin('\(dataForJS)')") { (result, error) in
}
webView.isHidden = true
activityIndicator.isHidden = false
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
let urlRequest = URLRequest(url: self.deepLinkURL!)
self.webView.load(urlRequest)
self.isUsedDeepLink = true
}
} else {
self.webView.isHidden = false
self.activityIndicator.isHidden = true
}
}
}
//segue to login screen and logout from smooch
func goToLoginScreen(){
Smooch.logout {(error:Error?, userInfo:[AnyHashable : Any]?) in
}
userDefaults.removeObject(forKey: "data")
performSegue(withIdentifier: "loginViewController", sender: self);
}
// check if token is valid . if not, go to login screen
func checkToken(){
if let token = userDefaults.dictionary(forKey: "data")?["access_token"]{
serverManager.checkToken(token: token as! String) { (code) in
if(code == "200"){
print("token is valid")
}else if(code == "401"){
print("token expierd")
self.goToLoginScreen()
}
}
}
}
// connect to smooch service , init and login
func initSmooch(){
guard let appId = responseData["smoochAppId"] ,let userId = responseData["smoochUserId"], let smoochToken = responseData["smoochJWTToken"] else {
chatBtnOutlet.isHidden = true
return
}
Smooch.initWith(SKTSettings(appId: appId as! String)) { (error:Error?, userInfo:[AnyHashable : Any]?) in
if(error == nil){
print("smooch init success")
Smooch.login(userId as! String , jwt: smoochToken as! String, completionHandler: { (error:Error?, userInfo: [AnyHashable : Any]?) in
if(error == nil){
print("smooch user login success")
}else{
print("smooch user login failed")
}
})
}else{
print("smooch init failed")
}
}
}
// listen to js event
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if(message.name == "finishLoading"){
print("finishLoading")
}else if (message.name == "logout"){
userDefaults.set(false, forKey: "isLoggedIn")
self.goToLoginScreen()
}
}
And here appDelegate where I'm using Universal link:
// MARK: - Deep Linking
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else { return false }
var viewController = UIViewController()
let userDefaults = UserDefaults.standard
let isLoggedIn = userDefaults.bool(forKey: "isLoggedIn")
if url.path == "/login" || isLoggedIn == false {
viewController = self.getDestinationLogin(for: url)
} else {
viewController = self.getDestinationMain(for: url)
}
externalUrl = url
window?.rootViewController = viewController
window?.makeKeyAndVisible()
return (parseAppLinks(from: url) != nil)
}
func getDestinationLogin(for url: URL) -> UIViewController {
let storyboard = UIStoryboard(name: "Main", bundle: .main)
let loginVC = storyboard.instantiateViewController(withIdentifier: "loginViewController") as? LoginViewController
return loginVC!
}
func getDestinationMain(for url: URL) -> UIViewController {
let storyboard = UIStoryboard(name: "Main", bundle: .main)
let mainVC = storyboard.instantiateViewController(withIdentifier: "MainViewController") as? MainViewController
let userDefaults = UserDefaults.standard
userDefaults.set(true, forKey: "isLoggedIn")
return mainVC!
}
private func parseAppLinks(from url: URL) -> String? {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { return .none }
guard let urlString = components.queryItems?.first?.value else { return .none }
return urlString
}