0

Following the apple documentation and Branch's documentation here, I have set up a working universal link in my Nativescript Angular (iOS) app. But, how do I parse the link when the app opens?

For example, when someone opens the app from the link, I want to have my app read the link so it can go to the correct page of the app.

There is some helpful code in this answer, but I keep getting errors with it. This could be bc the code is written in vanilla JS and I am not translating it into Angular correctly. The use of "_extends" and "routeUrL" both cause errors for me.

And the Nativescript url-handler plugin does not seem to work without further code.

So, after setting up the universal link, and installing the nativescript url-handler plugin, I have entered the following in app.module.ts:

const Application = require("tns-core-modules/application");

import { handleOpenURL, AppURL } from 'nativescript-urlhandler';
declare var NSUserActivityTypeBrowsingWeb

if (Application.ios) {   
  const MyDelegate = (function (_super) {

   _extends(MyDelegate, _super);
    function MyDelegate() {
      _super.apply(this, arguments);
    }
    MyDelegate.prototype.applicationContinueUserActivityRestorationHandler = function (application, userActivity) {
      if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
        this.routeUrl(userActivity.webpageURL);
      }
      return true;
    };
    MyDelegate.ObjCProtocols = [UIApplicationDelegate];
    return MyDelegate;
  })(UIResponder);
  Application.ios.delegate = MyDelegate;
}

...
export class AppModule {

ngOnInit(){
        handleOpenURL((appURL: AppURL) => {
            console.log('Got the following appURL = ' + appURL);
        });
    } 
}

The trouble seems to be mostly with "_extends" and "_super.apply". For example, I get this error:

'NativeScript encountered a fatal error: TypeError: undefined is not an object (evaluating '_extends')

EDIT: Note that the nativescript-urlhandler plugin is no longer being updated. Does anyone know how to parse universal links with Nativescript?

SeanRtS
  • 1,005
  • 1
  • 13
  • 31
  • 1
    First of the the plugin was updated recently 3 months ago and when I checked last time it used to support query params. The SO thread you are referring to is at least a year old. Follow the plugin docs and if you encounter any issue, please post complete error log. – Manoj Sep 23 '19 at 12:46
  • I have indeed followed the plugin documentation without success. Other are having similar issues as well: https://github.com/hypery2k/nativescript-urlhandler/issues/88 – SeanRtS Sep 23 '19 at 12:49
  • 1
    Please share the sample project where the issue can be reproduced. – Manoj Sep 23 '19 at 12:50
  • See the code in the edit for further detail. Please note the plugin is geared specifically toward deep links. The documentation does not address universal links, and its unclear whether the plugin works at all for universal links. Saying "just look at the plugin docs" is not an appropriate answer. If your downvote is simply bc "the plugin is updated but the so thread is older" please remove. The SO thread is still relevant. It was just updated literally yesterday. – SeanRtS Sep 23 '19 at 12:51
  • I had not got a chance to test Universal Links myself, the plugin has it implemented though. So if you have a sample project, may be I can take a look. – Manoj Sep 23 '19 at 13:12
  • I don't have a separate project that I can share. The issue is about startup of the app, so other components should not be relevant. The code posted here is the key. An important step is to figure out how, in Angular, I should write the "_extends..." and "_super.apply...". It would be very helpful to be able to move past the errors on those. – SeanRtS Sep 23 '19 at 14:55
  • `__extends` sounds like a helper function from TypeScript. You must be missing the additional `_` at the front. – Manoj Sep 23 '19 at 14:57
  • The code above is taken from a vanilla javascript example. How would you write "_extends" from vanilla JS in Angular? – SeanRtS Sep 23 '19 at 15:53
  • As I already mentioned `__extends` is a helper function defined globally, packed within core modules. The name comes form TSLib. – Manoj Sep 23 '19 at 15:59
  • Do you know the correct syntax to use it? Declaring it with "declare var _extends" does not help, and neither does using "this.extends" instead. – SeanRtS Sep 23 '19 at 16:40
  • As I already told you, you seem to be missing an extra underscore (_) at the front - There are 2 underscores before extends (`__extends`). You don't have to declare anything. – Manoj Sep 23 '19 at 16:41

2 Answers2

0

I have figured out a method to get this working:

The general idea is to use the iOS App Delegate method: applicationContinueUserActivityRestorationHandler.

The syntax in the Nativescript documentation on app delegates did not work for me. You can view that documentation here.

This appears to work:

--once you have a universal link set up, following documentation like here, and now you want your app to read ("handle") the details of the link that was tapped to open the app:

EDIT: This code sample puts everything in one spot in app.module.ts. However, most of the time its better to move things out of app.module and into separate services. There is sample code for doing that in the discussion here. So the below has working code, but keep in mind it is better to put this code in a separate service.

app.module.ts

    declare var UIResponder, UIApplicationDelegate
    if (app.ios) {
        app.ios.delegate = UIResponder.extend({
            applicationContinueUserActivityRestorationHandler: function(application, userActivity) {
                if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
                    let tappedUniversalLink = userActivity.webpageURL
                    console.log('the universal link url was = ' + tappedUniversalLink)
                } 
                return true;
            }
        },
        {
           name: "CustomAppDelegate",
            protocols: [UIApplicationDelegate]
        });
   }

NOTE: to get the NSUserActivity/Application Delegate stuff to work with typescript, I also needed to download the tns-platforms-declarations plugin, and configure the app. So:

$ npm i tns-platforms-declarations

and

references.d.ts

/// <reference path="./node_modules/tns-platform-declarations/ios.d.ts" />

The above code works for me to be able to read the details of the tapped universal link when the link opens the app.

From there, you can determine what you want to do with that information. For example, if you want to navigate to a specific page of your app depending on the details of the universal link, then I have found this to work:

app.module.ts

    import { ios, resumeEvent, on as applicationOn, run as applicationRun, ApplicationEventData } from "tns-core-modules/application";

    import { Router } from "@angular/router";

    let univeralLinkUrl = ''

    let hasLinkBeenTapped = false

    if (app.ios) {
       //code from above, to get value of the universal link
        applicationContinueUserActivityRestorationHandler: function(application, userActivity) {
                if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
                   hasLinkBeenTapped = true  
                   universalLinkUrl =  userActivity.webpageURL
                } 
                return true;
        },

            {
                name: "CustomAppDelegate",
                protocols: [UIApplicationDelegate]
            });

    }

    @ngModule({...})

    export class AppModule {
       constructor(private router: Router) {

            applicationOn(resumeEvent, (args) => {
               if (hasLinkBeenTapped === true){
                   hasLinkBeenTapped = false  //set back to false bc if you don't app will save setting of true, and always assume from here out that the universal link has been tapped whenever the app opens
                   let pageToOpen = //parse universalLinkUrl to get the details of the page you want to go to
                   this.router.navigate(["pageToOpen"])
                } else {
                    universalLinkUrl = '' //set back to blank
                    console.log('app is resuming, but universal Link has not been tapped') 
                }
            })
        }
    }
SeanRtS
  • 1,005
  • 1
  • 13
  • 31
0

You can use the nativescript-plugin-universal-links plugin to do just that. It has support for dealing with an existing app delegate so if you do have another plugin that implements an app delegate, both of them will work.

Here's the usage example from the docs:

import { Component, OnInit } from "@angular/core";
import { registerUniversalLinkCallback } from "nativescript-plugin-universal-links";

@Component({
  selector: "my-app",
  template: "<page-router-outlet></page-router-outlet>"
})
export class AppComponent {
  constructor() {}

  ngOnInit() {
    registerUniversalLinkCallback(ul => {
      // use the router to navigate to the screen
    });
  }
}

And the callback will receive a ul (universal link) param that looks like this

{
  "href": "https://www.example.com/blog?title=welcome",
  "origin": "https://www.example.com",
  "pathname": "/blog",
  "query": {
     "title": "welcome"
  }
}

Disclaimer: I'm the author of the plugin.