Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handleOpenURL() does not seem to be triggered when cliking a link when the App is closed #2

Closed
orenagiv opened this issue Nov 14, 2013 · 64 comments

Comments

@orenagiv
Copy link

Hi there,

The plugin seems to be working fantastic!
Once question though - The handleOpenURL(url) function does not seem to be triggered when clicking a link when the App is closed. It seems to work perfectly if the App is working in the background.

(Tested with PhoneGAP Build 3.1)

Thanks!
Oren.

@EddyVerbruggen
Copy link
Owner

Hi Oren, thanks!

Let's see if we can tackle this.. are you refering to iOS or Android? And is it possible to have a look at your code? Maybe a github url, or a private mail to eddyverbruggen[at]gmail.com?

@orenagiv
Copy link
Author

Hi Eddy,

So far testing on iOS (soon will test on Android).

The code is very simple:

function handleOpenURL(url) {
// This function is triggered by the LaunchMyApp Plugin
setTimeout(function() {
alert(url);
}, 400);
}

However - please note that this function is defined inside an EXTERNAL JS file.
So maybe when the App launches - that function does not "exist" yet, because the external JS file has not yet finished downloading..?

@EddyVerbruggen
Copy link
Owner

Hi Oren,

Yes, that could very well be the case! On iOS, the handleOpenURL is called from native code when the device is getting ready.. and that is likely to happen before any external content is loaded.

Could you inline the function in your index.html and check if it fires? Thanks!

@orenagiv
Copy link
Author

Yes - will check ASAP.
Just a thought - maybe it will be useful to use a global JS variable instead of triggering the handleOpenURL function? (or in addition)
This way the global JS var will be available anytime anywhere.
Actually - I'm going to use the handleOpenURL function to do just that:

function handleOpenURL(url) {
// This function is triggered by the LaunchMyApp Plugin
setTimeout(function() {
some_global_variable = url;
}, 400);
}

@EddyVerbruggen
Copy link
Owner

Not a bad idea and totally doable. However, the JS still needs to be triggered, so you know when to check for a (change to) the global variable. On coldstart you can have a startup check, but while running, you need to be triggered to check it. So indeed, a combination of these would work best: having the handleOpenURL function as it is now and being able to programmatically check a global variable (or a session variable).

Thanks for the idea, I will keep this issue open as a reminder.

@orenagiv
Copy link
Author

I can confirm that if the handleOpenURL() function is placed in the index.html HEAD - then it's working as expected!
I'm still "fighting" to get it propagate into the rest of the JS object of mine. Once I get something working - will post it here.

@orenagiv
Copy link
Author

Okay.. this is very weird. What happens for me is that only the first command inside the handleOpenURL() function gets triggered when the App launches for the first time.
However, if the App is already open - everything works properly.

For example:

    <head>
        ...
        <script>
            function handleOpenURL(url) {
                alert(1);
                alert(2);
            }
            ...
            document.addEventListener('deviceready', function() {
                // Inits the rest of the App
            }, false);
        </script>
    </head>

If your click a link (e.g. mycoolapp://something?key=value) and the App is CLOSED - the handleOpenURL() will do "alert(1)" and nothing else.
However, if the App is already working in the background - it will fire both alert(1) and alert(2).

Any ideas..? (tested on iOS7)

Thanks,
Oren.

@orenagiv orenagiv reopened this Nov 14, 2013
@EddyVerbruggen
Copy link
Owner

Hi,

I don't have an iOS device on me these days, but I can imagine it works the way you describe.

The iOS hook for this plugin is quite different from Android, and it seems part of the startup cycle of phonegap to invoke the javascript function. I guess it's some internal thingy we should not care too much about.

Is it a problem in real code? I think you can do all the stuff you need to do and just don't alert anything anyway ;)

@orenagiv
Copy link
Author

The alert was just an example.
The problem is that only the first command inside that function seems to work. Anything else is neglected.

But I need to keep drilling down into this to be sure.

My problem is this:
I need the App to parse the parameters from the URL and redirect the user to a specific location in the App.
That is why I need the handleOpenURL function to "wait" until the rest if the App (from the external JS) is loaded, and only then fire the "redirection" process.

Even if I am right - and there is some weird issue with the function in iOS - I will find a workaround and post it here shortly.

@orenagiv
Copy link
Author

Okay - managed to find a workaround:
If the handleOpenURL() function has a timeout of 3000 seconds or above - it works (even if the App is initially closed when clicking the external link).

I do not know why the 3 seconds delay is required.. so that's not a bullet-proof solution - but it works quite reliably on both Android and iOS.

The following example shows how to wait for an external JS object to load (myAppObject) and once it exists - a myAppObject variable "target_url" is set so that it can then be used internally whenever required.
And the function myAppObject.handle_url() is used to extract the URL parameters, so that you can then redirect the user to wherever you want inside the App or do whatever you want with those parameters.

The handleOpenURL() function MUST reside in the index.html of the local WWW folder:

function handleOpenURL(url) {
    setTimeout(function() {
        // This function is triggered by the LaunchMyApp Plugin
        if (!myAppObject) {
            handleOpenURL(url);
        } else {
            myAppObject.target_url = url;
            myAppObject.handle_url();
        }
        // This timeout of at least 3 seconds is necessary - otherwise the handleOpenURL() function does not work when an external link is clicked and the App is closed.
    }, 3000);
}

myAppObject - handle_url() example:

myAppObject:{

    target_url:null,
    target_url_params:{},

    handle_url_params:function() {
        params = myAppObject.target_url_params;
        if (params.example_param_1 || params.example_param_2) {
            // Got your parameters - now you can do whatever you want :)
        }
        // We can now "forget" the target_url
        myAppObject.target_url = null;
    },

    handle_url:function() {
        var params = {};
        if (myAppObject.target_url) {
            // target_url must be of the following format: prefix://something?key1=value1&key2=value2...
            var parts = myAppObject.target_url.replace(/^.+:\/\/[^?]*\?(.+)/, '$1').split('&');
            for (var i = 0; i < parts.length; i++) {
                var nv = parts[i].split('=');
                if (nv[0] && nv[1]) {
                    params[nv[0]] = nv[1];
                }
            }
        }
        myAppObject.target_url_params = params;
        if (params.example_param_1 || params.example_param_2) {
            myAppObject.handle_url_params();
        }        
    }

}

Hope someone will find this useful :)
Enjoy! And many thanks to Eddy!!! :)

@kaansoral
Copy link

Thanks Eddy for the awesome plugin and thanks Oren for sharing your experiences.

I've tested the plugin on both iOS and Android, it works like a charm, on both iOS and Android it did seem like the app was always being relaunched with an url scheme click, however I didn't verify

I think this plugin deserves more love, it might be a good idea to make the name more explanatory like "Custom URL Scheme" for it to be discovered better at Phonegap Plugins

The reason I'm hijacking this issue is:
https://developers.facebook.com/docs/ios/link-to-your-native-app-ios-sdk/

It seems facebook is calling apps with a custom url scheme of it's own, would "LaunchMyApp" catch these urls too?
(I couldn't test it myself as the deep links on facebook always redirect to Google Play instead of the app - another challenge for me)

@EddyVerbruggen
Copy link
Owner

Hi,

@kaansoral Yes, I'm pretty sure those fb callbacks are caught by this plugin as well.
I like the idea of renaming the plugin to make it more clear. Will consider it!

@orenagiv Is the myAppObject function defined in an external or local JS file?

Thanks guys!!
Eddy

@orenagiv
Copy link
Author

Hey guys,

Sorry for my extermely late response :) Only now noticed Eddy was asking a question... Better late than never :)

Eddy - the myAppObject function in my example above is defined in an EXTERNAL JS file.

@orenagiv
Copy link
Author

Hi Eddy,
Any chance you can contact me @ orenagiv@gmail.com ?

@Netpolice
Copy link

The function handleOpenURL not called even I put in in the top of index.js. Even set the timeout with 4000 value, this function doesn't call also when the application is closed.
However, if the application is running in the background, then there is no problem. This function will be called.

@terikon
Copy link

terikon commented Aug 9, 2014

Hi Eddy.
Thank you for this plugin, I find it very useful for my needs.
I would like to reopen the issue and provide solution that you will hopefully commit.

Here it goes.

  1. I experienced the issue on Android 4.1.5/Cordova 3.5

  2. My handleOpenURL function defined at index.html. I don't think this is important though.

  3. When my app runs on background, a link with custom schema executes handleOpenURL.

  4. When my app is not active, the handler is not being executed with somewhat 50% chance.

  5. I don't think solution that Oren proposed works (using setTimeout).

  6. Let's dig into the internals.

  7. From my investigation it seems that sometimes (here's the 50% probability) deviceready event fired 2 times when the app started anew. This causes triggerOpenURL() function of LaunchMyApp.js to be executed twice.
    First time it happens with intent data initialized, but (for reason unknown to me) the handleOpenURL handler is not executed. The second time deviceready event causes triggerOpenURL() to run once again, this time handleOpenURL does not execute for simple reason - see LaunchMyApp.java. The execute() and onNewIntent() methods here remove intent data each time they called. This due following row:

    intent.setData(null);

    that appears twice.

  8. I removed both rows

    intent.setData(null);

    I think there would not be any sacrifice in keeping the intent data.

  9. This resolves the problem completely in my case - from any tested condition the parameter given to a link
    will arrive in handleOpenURL handler - no matter the app running at background or not.

Hope this will improve the plugin.

@code4jhon
Copy link

handleOpenURL is not firing but i am using a plugin https://github.com/code4jhon/org.apache.cordova.startapp to open the app from another cordova app would this prevent handleOpenURL to fire?

@code4jhon
Copy link

got it working, was a permission issue when adding plugin ... some configs and files where not been added. Will try to make a post about this plugin used in Sencha Touch 2.3 / Cordova 3.5 apps.

Regards.

@EddyVerbruggen
Copy link
Owner

Cool thanks, and glad you figured it out before I found time to take a look 👍

@FreakTheMighty
Copy link

I'm seeing the same behavior as other people. @Netpolice pretty much sums it up, the plugin works when the app is backgrounded, but the callback does not fire, despite being defined in the head of my index.

I haven't dug too deep to investigate the cause, but the timeout fix that people are suggesting, seem like workarounds rather than best practice.

@terikon you're post mentions that you have a solution that you hope can be merged, but I don't see a merge request. Do patches exist somewhere?

@FreakTheMighty
Copy link

I've added a state variable that simply stores the latest url. This is inspired by @aabilio's comment in #29 where he suggested storing the url in localstorage as a fromurl. Between the callback, and leaving this breadcrumb, I'm able to handle both backgrounded and fully closed apps on Android.

I still don't understand why handleOpenURL isn't defined on launch, so this patch might still be a hack around some undefined problem.

FreakTheMighty@e5db611

@84pennies
Copy link

@EddyVerbruggen I am running the latest version of cordova as of right now and have just recently uninstalled and reinstalled the launchmyapp plugin just to be safe. I have also read the entire thread and tried all relevant solutions.

Issue: When a url launches the app on iOS from a coldstart (not running in the background) the handleOpenUrl() never fires. Ive tried putting it in the head and tried various ways of utilizing setTimeout. It works like a charm when the app is already in the background and it launches. I am able to grab the launch url and do what I need with it. This is how I was planning to implement.

In the head or somewhere near the start of my index.html have this:

var handleOpenUrl = function (url) { sessionStorage.setItem('openUrl', url); }
I can check that sessionStore item when the app is launching and do what I need to do.

Then after my app has initialized, I would redefine the variable like so:

handleOpenUrl = function (url) { //do more than before since app is now running }

The problem still stands that I can't get the handleOpenUrl to fire at all when it is launched from cold. If it is worth noting, I am getting this in my console in Xcode:

  • [CDVCommandQueue executePending] [Line 158] FAILED pluginJSON = [
    "INVALID",
    "LaunchMyApp",
    "checkIntent",
    [

    ]
    ]

Any help you could provide would definitely make my week at work go easier :)

@EddyVerbruggen
Copy link
Owner

@84pennies Did you perhaps install the plugin manually? That console log indicates you have added the Android version of launchmyapp.js to your iOS project!

@84pennies
Copy link

@EddyVerbruggen Thanks so much for the quick reply! Really appreciate it.

For reference, I am using one cordova project and I am not using phone gap build. I installed the plugin automatically using the cordova CLI command on the github readme. There seems to be a lot of contention amongst answers out there about what to put and not put in the config.xml when installing plugins in the current version of Cordova, so maybe something is amiss there? For the record, I currently don't have anything specific to your plugin in the config.xml (although I did have what was recommended in the readme at one point) and the behavior I am getting in iOS hasn't changed. I do still have everything in the androidmanifest.xml but I haven't tested on Android in a couple days.

But still, I am a little miffed why it would be working when the app is already running if that had something to do with it.

Do you have a recommended way of handling the different platforms when using one project? Right now there's only one www folder being used by both platforms (android and iOS) and it has the js file that is supposed to be used for Android. I suppose I could swap it out when i do builds but that seems cumbersome... Or I could manually copy it into the compiled www folder within the platform dir. But again... not the best it seems.

Do you think this console error has something to do with the issue? I noticed that this plugin doesn't have a CDV file in Xcode anything to worry about there?

@EddyVerbruggen
Copy link
Owner

@msalman That's not the Cordova-iOS version but the CLI version. Which Cordova-iOS version are you on? Problems arise with 3.7.0 and up.

@msalman
Copy link

msalman commented Jan 14, 2015

I use cordova -v to check the cordova version. In cordova lib project version file contains 3.7.0.

cordova platform version ios
Installed platforms: android 3.6.4, ios 3.7.0

sorry for being dumb, I am new to this.

@EddyVerbruggen
Copy link
Owner

Yeah, 3.7.0 has the bug. Hopefully https://issues.apache.org/jira/browse/CB-7606 will be resolved in time for 3.8.0.

@EddyVerbruggen
Copy link
Owner

Shazron has fixed the bug for 3.8.0 - I just tested it and it works fine :)

@kaansoral
Copy link

Off topic, I recently inspected the cordova cli/platform versioning and how the cli handles platform libraries (mainly to write a tool to know when a new platform version is available and live)
How did you manage to test 3.8.0 manually, as the CLI seems to fetch 3.7.0 as hard coded in 4.2.0?
(I guess you can trick the CLI by editing that hard coded version, but I'm just wondering whether there is an easy/obvious way)

@EddyVerbruggen
Copy link
Owner

Hi. Yeah, Shazron explained how to do this in the apache issue mentioned above. See his test-steps.

@kaansoral
Copy link

Thanks a lot for the pointer, it's very very helpful, After spending years hunting various mobile/cordova/webkit issues like these, it makes sense to just track https://git-wip-us.apache.org/repos/asf and add plugins/platforms manually when there are fixes that would take a long time to reach production, I'm even thinking of implementing a custom routine to parse for such changes and report them automatically / suggest utilising manual versions / upgrades

@laurilehmijoki
Copy link

I manually applied the fix into my Cordova iOS 3.7.0 project, because I was unable to upgrade to 3.8.0 via cordova plugin update ios.

Note to my future self: once the Cordova iOS 3.8.0 is available via the command cordova plugin update ios, revert the manual application of the fix and then run cordova plugin update ios.

@EddyVerbruggen
Copy link
Owner

Cordova-ios 3.8.0 has just been released, including the fix for CB-7606. This should fix your trouble, thanks for the patience.

@mirko77
Copy link

mirko77 commented Apr 22, 2015

@EddyVerbruggen I am using 3.8 now and handleOpenURL() is called upon cold start but NOT when the app is just resumed (as already opened). I am testing on iOS 7 & 8, is this the expected behaviour?

@symbiat
Copy link

symbiat commented Jun 16, 2015

@EddyVerbruggen
Copy link
Owner

@symbiat I like it

@qkdreyer
Copy link

qkdreyer commented Jul 9, 2015

I'm using the new PhoneGap Build version cli-5.1.1 and still experiencing this issue, on iOS.

handleOpenURL fires nicely when app is in the background, but not lauching from cold start.

@alexszilagyi
Copy link

@qkdreyer : Facing the same thing, have you managed to solve this? Thanks!

@qkdreyer
Copy link

Not yet sadly :/

@amardeepthadisetty
Copy link

Hi, I have used custom url plugin in my app and build it using phonegap build.
Here is my code:

<script type="text/javascript" src="phonegap.js"></script>
<script type="text/javascript">
    $(document).ready(function(){
        //alert("hello");
        var delay = 3000; //Your delay in milliseconds

        setTimeout(function(){
         window.location = "home.html";
       }, delay);
        document.addEventListener("deviceready", onDeviceReady, false);

        function onDeviceReady() {
        // Now safe to use the Cordova API
        alert("device is ready");

        function handleOpenURL(url) {
          setTimeout(function() {
            alert("received url: " + url);
          }, 0);
        }
    }

    });//end of document ready
    </script>

//end of code
I have opened a url in my mobile browser(http://fornextit.com/south/test.html) and clicked on the link of my app. My app is opening however the url is not firing. Please help........

@easym0de
Copy link

Cold Start Still not working for me.

Using cordova CLI 5.1.1 and Cordova iOS version 3.8.0.

Works fine in android and in iOS app running in background mode.

When tried with cold start, app runs but handleOpenURL never fired.

@easym0de
Copy link

OK I fixed the issue for "Cordova CLI 5.1.1 - Cordova iOS version 3.8.0" by doing the following:

Inside CDVHandleOpenURL.m:

Changed

NSString* jsString = [NSString stringWithFormat:@"document.addEventListener('deviceready',function(){if (typeof handleOpenURL === 'function') { handleOpenURL(\"%@\");}});", url];

to

NSString* jsString = [NSString stringWithFormat:@"if (typeof handleOpenURL === 'function') { handleOpenURL(\"%@\");} else { window._savedOpenURL = \"%@\"; }", url, url];

Then in Javascript code, introduced the following:

setTimeout(function() {
    if(typeof window._savedOpenURL != 'undefined'){
        window.handleOpenURL(window._savedOpenURL);
    }
}, 0);

Hope this helps.

@souly1
Copy link

souly1 commented Nov 26, 2015

@symbiat, great reference, thanks!

@yagao0o
Copy link

yagao0o commented Dec 17, 2015

@easym0de
Thanks,It work for me.
cordova CLI 5.4.1 and cordova iOS 3.8.0

@pushpendra996
Copy link

Hi, There
I am trying to open a another tab on link click but it direct goes to the home screen means goes to the (Login) which i have set into run() method.
i had try to catch the URL by witch i am trying to come on the app. but i think so my

function handleOpenURL(url) {
setTimeout(function () {
var event = new CustomEvent('LaunchUrl', {detail: {'url': url}});
alert (event);
window.dispatchEvent(event);
}, 0);
}

function is not working. is any one here what should i do.................

@laxmikantp38
Copy link

Hello Guy's,

You can easily sort out this problem.

In "CDVHandleOpenURL.m" file you need to change code as below

NSString* jsString = [NSString stringWithFormat:@"document.addEventListener('deviceready',function(){if (typeof handleOpenURL === 'function') { handleOpenURL("%@");}});", url];

To

NSString* jsString = [NSString stringWithFormat:@"if (typeof handleOpenURL === 'function') { handleOpenURL("%@");} else { window._savedOpenURL = "%@"; }", url, url];

this will work perfectly.

Best of luck

@srsarcasmo
Copy link

hola, si el plugin funciona bien en ambas plataformas..
el detalle es cuando lo que quieres es seleccionar de un select o una lista el archivo a visualizar¡¡ .. aqui hay un dilema porque del id correspondiente debe asociarse la URL del archivo..

pero, como hacer esto?

moses pushed a commit to flarehealth/cordova-ios that referenced this issue Sep 27, 2016
@celron
Copy link

celron commented Oct 19, 2016

Great work from @easym0de, this solution to update the cordova platform code solved the problem for me. What ways is there to package it into something that can be added to the git://git.apache.org/cordova-ios.git to make a more permanent solution?

@rondoe
Copy link

rondoe commented Jan 5, 2017

In my case the problem was solved after adding gap://ready to my Content-Security-Policy. I was wondering why safari gave me so many errors with gap://ready. so i added it, and it was solved. now handleOpenURL works as expected.

@abdurraqeeb
Copy link

How can i make a script that if anyone visits my website then his default home page is my websites URL

@emirhosseini
Copy link

None of these solutions work for me. Still having this issue in 2018. Navigating to a hosted login page, logging in which then redirects back to the app. Works fine in iOs emulator and android. Just not on actual ios device...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests